<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>八股文-001 | 前端档案</title>
    <meta name="generator" content="VuePress 1.8.2">
    <link rel="icon" href="/favicon.ico">
    <meta name="description" content="前端通关宝典">
    <meta name="theme-color" content="#3eaf7c">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    
    <link rel="preload" href="/assets/css/0.styles.e02fc531.css" as="style"><link rel="preload" href="/assets/js/app.bf44e39b.js" as="script"><link rel="preload" href="/assets/js/2.db7a59af.js" as="script"><link rel="preload" href="/assets/js/266.97118d6c.js" as="script"><link rel="prefetch" href="/assets/js/10.3bbe2f24.js"><link rel="prefetch" href="/assets/js/100.43061c81.js"><link rel="prefetch" href="/assets/js/101.2e8a188c.js"><link rel="prefetch" href="/assets/js/102.3f4f14f0.js"><link rel="prefetch" href="/assets/js/103.5ed45f48.js"><link rel="prefetch" href="/assets/js/104.29ef9283.js"><link rel="prefetch" href="/assets/js/105.e4051d70.js"><link rel="prefetch" href="/assets/js/106.ec073f00.js"><link rel="prefetch" href="/assets/js/107.9b165150.js"><link rel="prefetch" href="/assets/js/108.c0031864.js"><link rel="prefetch" href="/assets/js/109.06bb75a7.js"><link rel="prefetch" href="/assets/js/11.402e3434.js"><link rel="prefetch" href="/assets/js/110.edc92528.js"><link rel="prefetch" href="/assets/js/111.e50e0cca.js"><link rel="prefetch" href="/assets/js/112.b0decdf4.js"><link rel="prefetch" href="/assets/js/113.f0801886.js"><link rel="prefetch" href="/assets/js/114.25ab8fa4.js"><link rel="prefetch" href="/assets/js/115.36fc62f3.js"><link rel="prefetch" href="/assets/js/116.8df9a6aa.js"><link rel="prefetch" href="/assets/js/117.1ec0fada.js"><link rel="prefetch" href="/assets/js/118.51c54869.js"><link rel="prefetch" href="/assets/js/119.d708669d.js"><link rel="prefetch" href="/assets/js/12.eba9a66a.js"><link rel="prefetch" href="/assets/js/120.a44efeea.js"><link rel="prefetch" href="/assets/js/121.581a4ae4.js"><link rel="prefetch" href="/assets/js/122.e54e19e1.js"><link rel="prefetch" href="/assets/js/123.62aa41d0.js"><link rel="prefetch" href="/assets/js/124.c51c6b7f.js"><link rel="prefetch" href="/assets/js/125.68055811.js"><link rel="prefetch" href="/assets/js/126.8b16d246.js"><link rel="prefetch" href="/assets/js/127.fc7608d6.js"><link rel="prefetch" href="/assets/js/128.0df431fc.js"><link rel="prefetch" href="/assets/js/129.77241cfd.js"><link rel="prefetch" href="/assets/js/13.a3e65817.js"><link rel="prefetch" href="/assets/js/130.2bf0b622.js"><link rel="prefetch" href="/assets/js/131.77da1093.js"><link rel="prefetch" href="/assets/js/132.c1ac84bc.js"><link rel="prefetch" href="/assets/js/133.001af559.js"><link rel="prefetch" href="/assets/js/134.98ff69db.js"><link rel="prefetch" href="/assets/js/135.b91963f4.js"><link rel="prefetch" href="/assets/js/136.e3df531a.js"><link rel="prefetch" href="/assets/js/137.157c5a5f.js"><link rel="prefetch" href="/assets/js/138.1d3a1791.js"><link rel="prefetch" href="/assets/js/139.9e17df54.js"><link rel="prefetch" href="/assets/js/14.bd9cc5f8.js"><link rel="prefetch" href="/assets/js/140.22839840.js"><link rel="prefetch" href="/assets/js/141.dbde614d.js"><link rel="prefetch" href="/assets/js/142.5a6858ba.js"><link rel="prefetch" href="/assets/js/143.e26d707c.js"><link rel="prefetch" href="/assets/js/144.5b1fbe13.js"><link rel="prefetch" href="/assets/js/145.09921e20.js"><link rel="prefetch" href="/assets/js/146.8ea606b7.js"><link rel="prefetch" href="/assets/js/147.41bda9d5.js"><link rel="prefetch" href="/assets/js/148.d89f18bc.js"><link rel="prefetch" href="/assets/js/149.16aa39c9.js"><link rel="prefetch" href="/assets/js/15.deb2f25a.js"><link rel="prefetch" href="/assets/js/150.07798494.js"><link rel="prefetch" href="/assets/js/151.6732ee94.js"><link rel="prefetch" href="/assets/js/152.c644167e.js"><link rel="prefetch" href="/assets/js/153.040f256b.js"><link rel="prefetch" href="/assets/js/154.1cec3035.js"><link rel="prefetch" href="/assets/js/155.a4b51a17.js"><link rel="prefetch" href="/assets/js/156.095b78e0.js"><link rel="prefetch" href="/assets/js/157.eb262a26.js"><link rel="prefetch" href="/assets/js/158.35756e8c.js"><link rel="prefetch" href="/assets/js/159.6ac43664.js"><link rel="prefetch" href="/assets/js/16.c7b17381.js"><link rel="prefetch" href="/assets/js/160.0a56c40c.js"><link rel="prefetch" href="/assets/js/161.8320b48a.js"><link rel="prefetch" href="/assets/js/162.09ba1172.js"><link rel="prefetch" href="/assets/js/163.f7fb82e8.js"><link rel="prefetch" href="/assets/js/164.ab9df42b.js"><link rel="prefetch" href="/assets/js/165.f012858f.js"><link rel="prefetch" href="/assets/js/166.b3f190e3.js"><link rel="prefetch" href="/assets/js/167.43b66e59.js"><link rel="prefetch" href="/assets/js/168.4eb162d3.js"><link rel="prefetch" href="/assets/js/169.0375d2cf.js"><link rel="prefetch" href="/assets/js/17.da61c942.js"><link rel="prefetch" href="/assets/js/170.90c9c235.js"><link rel="prefetch" href="/assets/js/171.672fc257.js"><link rel="prefetch" href="/assets/js/172.dfa9d8d9.js"><link rel="prefetch" href="/assets/js/173.61a6ec8e.js"><link rel="prefetch" href="/assets/js/174.4f4ef0d7.js"><link rel="prefetch" href="/assets/js/175.675d01d1.js"><link rel="prefetch" href="/assets/js/176.5bd1bcb7.js"><link rel="prefetch" href="/assets/js/177.4355dadd.js"><link rel="prefetch" href="/assets/js/178.79ed29b8.js"><link rel="prefetch" href="/assets/js/179.2247dc30.js"><link rel="prefetch" href="/assets/js/18.6e554767.js"><link rel="prefetch" href="/assets/js/180.db79361a.js"><link rel="prefetch" href="/assets/js/181.85a33295.js"><link rel="prefetch" href="/assets/js/182.0bc317bc.js"><link rel="prefetch" href="/assets/js/183.7769a38e.js"><link rel="prefetch" href="/assets/js/184.9b0aba05.js"><link rel="prefetch" href="/assets/js/185.f6dc87bd.js"><link rel="prefetch" href="/assets/js/186.e3b7de00.js"><link rel="prefetch" href="/assets/js/187.a6dadcea.js"><link rel="prefetch" href="/assets/js/188.d3f8b0e3.js"><link rel="prefetch" href="/assets/js/189.1112499f.js"><link rel="prefetch" href="/assets/js/19.f800e0d1.js"><link rel="prefetch" href="/assets/js/190.e3255e84.js"><link rel="prefetch" href="/assets/js/191.34deece6.js"><link rel="prefetch" href="/assets/js/192.69821c0e.js"><link rel="prefetch" href="/assets/js/193.769a5088.js"><link rel="prefetch" href="/assets/js/194.afaa2cde.js"><link rel="prefetch" href="/assets/js/195.5b94bbc6.js"><link rel="prefetch" href="/assets/js/196.3b078264.js"><link rel="prefetch" href="/assets/js/197.2d9585d3.js"><link rel="prefetch" href="/assets/js/198.3095d8b8.js"><link rel="prefetch" href="/assets/js/199.79b6db11.js"><link rel="prefetch" href="/assets/js/20.4a74a968.js"><link rel="prefetch" href="/assets/js/200.c309ef7a.js"><link rel="prefetch" href="/assets/js/201.bded46e8.js"><link rel="prefetch" href="/assets/js/202.801fb3ea.js"><link rel="prefetch" href="/assets/js/203.b9933f5e.js"><link rel="prefetch" href="/assets/js/204.255b43df.js"><link rel="prefetch" href="/assets/js/205.000fb7ac.js"><link rel="prefetch" href="/assets/js/206.8f945829.js"><link rel="prefetch" href="/assets/js/207.74942b2e.js"><link rel="prefetch" href="/assets/js/208.329d8230.js"><link rel="prefetch" href="/assets/js/209.3fc54586.js"><link rel="prefetch" href="/assets/js/21.5f725cbd.js"><link rel="prefetch" href="/assets/js/210.1aa9659f.js"><link rel="prefetch" href="/assets/js/211.702df03f.js"><link rel="prefetch" href="/assets/js/212.ca95f208.js"><link rel="prefetch" href="/assets/js/213.024b4fa6.js"><link rel="prefetch" href="/assets/js/214.e2830dd8.js"><link rel="prefetch" href="/assets/js/215.0b646cb4.js"><link rel="prefetch" href="/assets/js/216.9bd6d019.js"><link rel="prefetch" href="/assets/js/217.586593b4.js"><link rel="prefetch" href="/assets/js/218.a2244829.js"><link rel="prefetch" href="/assets/js/219.1d858220.js"><link rel="prefetch" href="/assets/js/22.7d2b7a74.js"><link rel="prefetch" href="/assets/js/220.7f5e3dbd.js"><link rel="prefetch" href="/assets/js/221.d1f79d31.js"><link rel="prefetch" href="/assets/js/222.51d8a12c.js"><link rel="prefetch" href="/assets/js/223.797028ea.js"><link rel="prefetch" href="/assets/js/224.d925bf8b.js"><link rel="prefetch" href="/assets/js/225.cfe12606.js"><link rel="prefetch" href="/assets/js/226.b6bd41b4.js"><link rel="prefetch" href="/assets/js/227.15412d16.js"><link rel="prefetch" href="/assets/js/228.66af5157.js"><link rel="prefetch" href="/assets/js/229.cfb11559.js"><link rel="prefetch" href="/assets/js/23.1409c9f4.js"><link rel="prefetch" href="/assets/js/230.d2e613b5.js"><link rel="prefetch" href="/assets/js/231.85b8958b.js"><link rel="prefetch" href="/assets/js/232.42df48c8.js"><link rel="prefetch" href="/assets/js/233.d3be0c78.js"><link rel="prefetch" href="/assets/js/234.bb68d0be.js"><link rel="prefetch" href="/assets/js/235.bfd00052.js"><link rel="prefetch" href="/assets/js/236.3d58cc9d.js"><link rel="prefetch" href="/assets/js/237.d9af6062.js"><link rel="prefetch" href="/assets/js/238.54894974.js"><link rel="prefetch" href="/assets/js/239.b69669d0.js"><link rel="prefetch" href="/assets/js/24.e06b2b32.js"><link rel="prefetch" href="/assets/js/240.44f7b333.js"><link rel="prefetch" href="/assets/js/241.2d307b1a.js"><link rel="prefetch" href="/assets/js/242.47aecf42.js"><link rel="prefetch" href="/assets/js/243.b5afbb6e.js"><link rel="prefetch" href="/assets/js/244.8e04094f.js"><link rel="prefetch" href="/assets/js/245.78009475.js"><link rel="prefetch" href="/assets/js/246.eb7991c2.js"><link rel="prefetch" href="/assets/js/247.00c024fd.js"><link rel="prefetch" href="/assets/js/248.144c2842.js"><link rel="prefetch" href="/assets/js/249.35bae652.js"><link rel="prefetch" href="/assets/js/25.5e7aeaa8.js"><link rel="prefetch" href="/assets/js/250.854bde18.js"><link rel="prefetch" href="/assets/js/251.7cbb77f8.js"><link rel="prefetch" href="/assets/js/252.1ed96448.js"><link rel="prefetch" href="/assets/js/253.9d736b7d.js"><link rel="prefetch" href="/assets/js/254.137c6595.js"><link rel="prefetch" href="/assets/js/255.ac6865dc.js"><link rel="prefetch" href="/assets/js/256.055e06fd.js"><link rel="prefetch" href="/assets/js/257.63559614.js"><link rel="prefetch" href="/assets/js/258.b6958ba1.js"><link rel="prefetch" href="/assets/js/259.bc6da491.js"><link rel="prefetch" href="/assets/js/26.77d42111.js"><link rel="prefetch" href="/assets/js/260.a8e9559d.js"><link rel="prefetch" href="/assets/js/261.b051c6dd.js"><link rel="prefetch" href="/assets/js/262.e83c7ca8.js"><link rel="prefetch" href="/assets/js/263.bd14a165.js"><link rel="prefetch" href="/assets/js/264.65c3b624.js"><link rel="prefetch" href="/assets/js/265.db4371b9.js"><link rel="prefetch" href="/assets/js/267.de83cb0b.js"><link rel="prefetch" href="/assets/js/268.2bdd86cb.js"><link rel="prefetch" href="/assets/js/269.9c9a802f.js"><link rel="prefetch" href="/assets/js/27.fa37605f.js"><link rel="prefetch" href="/assets/js/270.f599f9fe.js"><link rel="prefetch" href="/assets/js/271.275d4619.js"><link rel="prefetch" href="/assets/js/272.ed0fabf6.js"><link rel="prefetch" href="/assets/js/273.fc279fbe.js"><link rel="prefetch" href="/assets/js/274.fe4b3d21.js"><link rel="prefetch" href="/assets/js/275.922677e1.js"><link rel="prefetch" href="/assets/js/276.597ceb81.js"><link rel="prefetch" href="/assets/js/277.71871d2e.js"><link rel="prefetch" href="/assets/js/278.10923657.js"><link rel="prefetch" href="/assets/js/279.cddbf2d7.js"><link rel="prefetch" href="/assets/js/28.7418a003.js"><link rel="prefetch" href="/assets/js/280.66542c64.js"><link rel="prefetch" href="/assets/js/281.c7ca5292.js"><link rel="prefetch" href="/assets/js/282.d105ef08.js"><link rel="prefetch" href="/assets/js/283.ae8d69c7.js"><link rel="prefetch" href="/assets/js/284.8763c337.js"><link rel="prefetch" href="/assets/js/285.cce4e007.js"><link rel="prefetch" href="/assets/js/29.42b5bf54.js"><link rel="prefetch" href="/assets/js/3.a2af090e.js"><link rel="prefetch" href="/assets/js/30.7fe0ece5.js"><link rel="prefetch" href="/assets/js/31.e05d012e.js"><link rel="prefetch" href="/assets/js/32.0a6466c6.js"><link rel="prefetch" href="/assets/js/33.8db270b1.js"><link rel="prefetch" href="/assets/js/34.c6e6ae70.js"><link rel="prefetch" href="/assets/js/35.8fc12d56.js"><link rel="prefetch" href="/assets/js/36.cb54baf3.js"><link rel="prefetch" href="/assets/js/37.656cb8eb.js"><link rel="prefetch" href="/assets/js/38.9152ff6b.js"><link rel="prefetch" href="/assets/js/39.f71e5e3d.js"><link rel="prefetch" href="/assets/js/4.02de3c47.js"><link rel="prefetch" href="/assets/js/40.3d664ab4.js"><link rel="prefetch" href="/assets/js/41.fc6e4f78.js"><link rel="prefetch" href="/assets/js/42.c17c3353.js"><link rel="prefetch" href="/assets/js/43.e78a329f.js"><link rel="prefetch" href="/assets/js/44.326a0948.js"><link rel="prefetch" href="/assets/js/45.67e6e1d4.js"><link rel="prefetch" href="/assets/js/46.85f71b1e.js"><link rel="prefetch" href="/assets/js/47.f2e524a6.js"><link rel="prefetch" href="/assets/js/48.843108ee.js"><link rel="prefetch" href="/assets/js/49.98713c95.js"><link rel="prefetch" href="/assets/js/5.f38c3daa.js"><link rel="prefetch" href="/assets/js/50.2c70898f.js"><link rel="prefetch" href="/assets/js/51.023fea5d.js"><link rel="prefetch" href="/assets/js/52.3877af4c.js"><link rel="prefetch" href="/assets/js/53.3938d117.js"><link rel="prefetch" href="/assets/js/54.4cf45721.js"><link rel="prefetch" href="/assets/js/55.6894de94.js"><link rel="prefetch" href="/assets/js/56.48fd0f63.js"><link rel="prefetch" href="/assets/js/57.2c3b8155.js"><link rel="prefetch" href="/assets/js/58.fee976b4.js"><link rel="prefetch" href="/assets/js/59.d57c3ac9.js"><link rel="prefetch" href="/assets/js/6.a7d50f34.js"><link rel="prefetch" href="/assets/js/60.9954df49.js"><link rel="prefetch" href="/assets/js/61.1b870f60.js"><link rel="prefetch" href="/assets/js/62.37537ac3.js"><link rel="prefetch" href="/assets/js/63.5e7cfac8.js"><link rel="prefetch" href="/assets/js/64.407003ca.js"><link rel="prefetch" href="/assets/js/65.ba6c5d7d.js"><link rel="prefetch" href="/assets/js/66.2b5a751b.js"><link rel="prefetch" href="/assets/js/67.2faf15d0.js"><link rel="prefetch" href="/assets/js/68.19e50dcb.js"><link rel="prefetch" href="/assets/js/69.eec003cb.js"><link rel="prefetch" href="/assets/js/7.6c196c91.js"><link rel="prefetch" href="/assets/js/70.98d2461a.js"><link rel="prefetch" href="/assets/js/71.184225a4.js"><link rel="prefetch" href="/assets/js/72.956d136a.js"><link rel="prefetch" href="/assets/js/73.3e68378e.js"><link rel="prefetch" href="/assets/js/74.cec669e7.js"><link rel="prefetch" href="/assets/js/75.d418b5f0.js"><link rel="prefetch" href="/assets/js/76.f3f9ccd6.js"><link rel="prefetch" href="/assets/js/77.f24df03b.js"><link rel="prefetch" href="/assets/js/78.7eee67a8.js"><link rel="prefetch" href="/assets/js/79.8fadb3f7.js"><link rel="prefetch" href="/assets/js/8.b7eb2fb2.js"><link rel="prefetch" href="/assets/js/80.4f6165b0.js"><link rel="prefetch" href="/assets/js/81.49b03807.js"><link rel="prefetch" href="/assets/js/82.7ea07224.js"><link rel="prefetch" href="/assets/js/83.d6bd71b7.js"><link rel="prefetch" href="/assets/js/84.26db1aa8.js"><link rel="prefetch" href="/assets/js/85.c8f1f3bb.js"><link rel="prefetch" href="/assets/js/86.fd1c3c7f.js"><link rel="prefetch" href="/assets/js/87.38ab6ed9.js"><link rel="prefetch" href="/assets/js/88.f0a874e0.js"><link rel="prefetch" href="/assets/js/89.2b3352d4.js"><link rel="prefetch" href="/assets/js/9.d7ae4925.js"><link rel="prefetch" href="/assets/js/90.286cc7d4.js"><link rel="prefetch" href="/assets/js/91.c17c366b.js"><link rel="prefetch" href="/assets/js/92.29bc2389.js"><link rel="prefetch" href="/assets/js/93.6d335097.js"><link rel="prefetch" href="/assets/js/94.89ab26c7.js"><link rel="prefetch" href="/assets/js/95.f2493183.js"><link rel="prefetch" href="/assets/js/96.6662ec36.js"><link rel="prefetch" href="/assets/js/97.22c9d3f9.js"><link rel="prefetch" href="/assets/js/98.0b0b77a2.js"><link rel="prefetch" href="/assets/js/99.df5f5981.js">
    <link rel="stylesheet" href="/assets/css/0.styles.e02fc531.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/images/logo.png" alt="前端档案" class="logo"> <span class="site-name can-hide">前端档案</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/guide/" class="nav-link">
  指南
</a></div><div class="nav-item"><a href="/fe/" class="nav-link">
  前端
</a></div><div class="nav-item"><a href="/be/" class="nav-link">
  后端
</a></div><div class="nav-item"><a href="/base/" class="nav-link">
  基础
</a></div><div class="nav-item"><a href="/tools/" class="nav-link">
  工具
</a></div><div class="nav-item"><a href="/resume/" class="nav-link">
  简历
</a></div><div class="nav-item"><a href="/experience/" class="nav-link">
  面经
</a></div><div class="nav-item"><a href="/technology/" class="nav-link router-link-active">
  八股文
</a></div><div class="nav-item"><a href="/thinks/" class="nav-link">
  思考
</a></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/guide/" class="nav-link">
  指南
</a></div><div class="nav-item"><a href="/fe/" class="nav-link">
  前端
</a></div><div class="nav-item"><a href="/be/" class="nav-link">
  后端
</a></div><div class="nav-item"><a href="/base/" class="nav-link">
  基础
</a></div><div class="nav-item"><a href="/tools/" class="nav-link">
  工具
</a></div><div class="nav-item"><a href="/resume/" class="nav-link">
  简历
</a></div><div class="nav-item"><a href="/experience/" class="nav-link">
  面经
</a></div><div class="nav-item"><a href="/technology/" class="nav-link router-link-active">
  八股文
</a></div><div class="nav-item"><a href="/thinks/" class="nav-link">
  思考
</a></div> <!----></nav>  <ul class="sidebar-links"><li><a href="/technology/" aria-current="page" class="sidebar-link">待整理部分</a></li><li><a href="/technology/excellent.html" class="sidebar-link">高频考点</a></li><li><a href="/technology/js_higher.html" class="sidebar-link">JS高级知识点</a></li><li><a href="/technology/eight_001.html" aria-current="page" class="active sidebar-link">八股文-001</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/technology/eight_001.html#http-和-https" class="sidebar-link">HTTP 和 HTTPS</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#tcp" class="sidebar-link">TCP</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#http-请求跨域问题" class="sidebar-link">HTTP 请求跨域问题</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#本地存储" class="sidebar-link">本地存储</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#浏览器从输入url到页面加载的全过程" class="sidebar-link">浏览器从输入URL到页面加载的全过程</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#重排和重绘" class="sidebar-link">重排和重绘</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#介绍下304过程" class="sidebar-link">介绍下304过程</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#浏览器缓存机制-强制缓存-协商缓存" class="sidebar-link">浏览器缓存机制 强制缓存 &amp;&amp; 协商缓存</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#进程、线程和协程" class="sidebar-link">进程、线程和协程</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#html5-新特性、语义化" class="sidebar-link">HTML5 新特性、语义化</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#css-选择器及优先级" class="sidebar-link">CSS 选择器及优先级</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#position-属性的值有哪些及其区别" class="sidebar-link">position 属性的值有哪些及其区别</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#box-sizing属性" class="sidebar-link">box-sizing属性</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#css-盒子模型" class="sidebar-link">CSS 盒子模型</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#bfc-块级格式上下文" class="sidebar-link">BFC（块级格式上下文）</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#让一个元素水平垂直居中" class="sidebar-link">让一个元素水平垂直居中</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#隐藏页面中某个元素的方法" class="sidebar-link">隐藏页面中某个元素的方法</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#用css实现三角符号" class="sidebar-link">用CSS实现三角符号</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#页面布局" class="sidebar-link">页面布局</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#如何使用rem或viewport进行移动端适配" class="sidebar-link">如何使用rem或viewport进行移动端适配</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#清除浮动的方式" class="sidebar-link">清除浮动的方式</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#js中的8种数据类型及区别" class="sidebar-link">JS中的8种数据类型及区别</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#js中的数据类型检测方案" class="sidebar-link">JS中的数据类型检测方案</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#var-let-const" class="sidebar-link">var &amp;&amp; let &amp;&amp; const</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#js垃圾回收机制" class="sidebar-link">JS垃圾回收机制</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#作用域和作用域链" class="sidebar-link">作用域和作用域链</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#闭包的两大作用-保存-保护" class="sidebar-link">闭包的两大作用：保存/保护</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#js-中-this-的五种情况" class="sidebar-link">JS 中 this 的五种情况</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#原型-原型链" class="sidebar-link">原型 &amp;&amp; 原型链</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#new运算符的实现机制" class="sidebar-link">new运算符的实现机制</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#eventloop-事件循环" class="sidebar-link">EventLoop 事件循环</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#settimeout、promise、async-await-的区别" class="sidebar-link">setTimeout、Promise、Async/Await 的区别</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#async-await-如何通过同步的方式实现异步" class="sidebar-link">Async/Await 如何通过同步的方式实现异步</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#介绍节流防抖原理、区别以及应用" class="sidebar-link">介绍节流防抖原理、区别以及应用</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#简述mvvm" class="sidebar-link">简述MVVM</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#vue底层实现原理" class="sidebar-link">Vue底层实现原理</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#谈谈对vue生命周期的理解" class="sidebar-link">谈谈对vue生命周期的理解？</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#vue中computed与watch区别" class="sidebar-link">Vue中computed与watch区别</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#react-vue-项目中-key-的作用" class="sidebar-link">React/Vue 项目中 key 的作用</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#vue组件的通信方式" class="sidebar-link">Vue组件的通信方式</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#nexttick的实现" class="sidebar-link">nextTick的实现</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#nexttick的实现原理是什么" class="sidebar-link">nextTick的实现原理是什么？</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#插槽" class="sidebar-link">插槽</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#keep-alive的实现" class="sidebar-link">keep-alive的实现</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#mixin" class="sidebar-link">mixin</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#vuex的理解及使用场景" class="sidebar-link">Vuex的理解及使用场景</a></li><li class="sidebar-sub-header"><a href="/technology/eight_001.html#项目优化" class="sidebar-link">项目优化</a></li></ul></li><li><a href="/technology/eight_002.html" class="sidebar-link">八股文-002</a></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="八股文-001"><a href="#八股文-001" class="header-anchor">#</a> 八股文-001</h1> <h2 id="http-和-https"><a href="#http-和-https" class="header-anchor">#</a> HTTP 和 HTTPS</h2> <h3 id="_1-概念"><a href="#_1-概念" class="header-anchor">#</a> 1. 概念</h3> <ul><li>http: 是一个客户端和服务器端请求和应答的标准（TCP），用于从 WWW 服务器传输超文本到本地浏览器的超文本传输协议。</li> <li>https: 是以安全为目标的 HTTP 通道，即 HTTP 下 加入 SSL 层进行加密。其作用是：建立一个信息安全通道，来确保数据的传输和真实性。</li></ul> <h3 id="_2-区别及优缺点"><a href="#_2-区别及优缺点" class="header-anchor">#</a> 2. 区别及优缺点</h3> <p><code>HTTP</code>是超文本传输协议，信息是明文传输，<code>HTTPS</code> 协议要比 <code>HTTP</code> 协议<strong>安全</strong>，<code>HTTPS</code> 是具有安全性的 <code>SSL</code> 加密传输协议，可防止数据在传输过程中不被窃取、改变，确保数据的完整性。</p> <blockquote><p>HTTP 主要特点：简单快速、灵活、无连接、无状态</p></blockquote> <ul><li><code>HTTP</code> 协议的<strong>默认端口</strong>为 80，<code>HTTPS</code> 的默认端口为 443</li> <li><code>HTTP</code> 的连接很简单，是无状态的。<code>HTTPS</code> 握手阶段比较<strong>费时</strong>，会使页面加载时间延长 50%，增加 10%~20%的耗电。</li> <li><code>HTTPS</code> 缓存不如 <code>HTTP</code> 高效，会增加数据开销。</li> <li><code>HTTPS</code>协议需要 ca 证书，费用较高，功能越强大的<strong>证书费</strong>用越高。</li> <li>SSL 证书需要绑定 <code>IP</code>，不能再同一个 IP 上绑定多个域名，IPV4 资源支持不了这种消耗。</li></ul> <h3 id="_3-https-工作原理"><a href="#_3-https-工作原理" class="header-anchor">#</a> 3. HTTPS 工作原理</h3> <p>客户端在使用 HTTPS 方式与 Web 服务器通信时有以下几个步骤：</p> <ol><li><strong>建立 ssl 链接</strong>：客户端使用 https url 访问服务器，则要求 web 服务器<code>建立 ssl 链接</code>。</li> <li><strong>传输证书</strong>：web 服务器接收到客户端的请求之后，会<code>将网站的证书（证书中包含了公钥），传输给客户端</code>。</li> <li><strong>协商安全等级</strong>：客户端和 web 服务器端开始<code>协商 SSL 链接的安全等级</code>，也就是加密等级。</li> <li><strong>建立会话密钥</strong>：客户端浏览器通过双方协商一致的安全等级，<code>建立会话密钥</code>，然后通过网站的公钥来加密会话密钥，并传送给网站。</li> <li><strong>解密密钥</strong>：web 服务器<code>通过自己的私钥解密出会话密钥</code>。</li> <li><strong>进行通信</strong>：web 服务器<code>通过会话密钥加密与客户端之间的通信</code>。</li></ol> <p>传送门 ☞ <a href="https://juejin.cn/post/6995109407545622542" target="_blank" rel="noopener noreferrer"># 解读 HTTP1/HTTP2/HTTP3(opens new window)<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <h2 id="tcp"><a href="#tcp" class="header-anchor">#</a> TCP</h2> <p><a href="https://zhuanlan.zhihu.com/p/199284611?from=timeline" target="_blank" rel="noopener noreferrer">彻底搞懂TCP协议：从 TCP 三次握手四次挥手说起 - 知乎 (zhihu.com)<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <h3 id="_1-tcp三次握手"><a href="#_1-tcp三次握手" class="header-anchor">#</a> 1. TCP三次握手</h3> <ol><li>第一次握手：服务器（S）只可以确认自己可以接受客户端（C）发送的报文段；</li> <li>第二次握手：客户端（C）可以确认服务器（S）收到了自己发送的报文段，并且可以确认自己可以接受服务器（S）发送的报文段；</li> <li>第三次握手：服务器（S）可以确认客户端（C）收到了自己发送的报文段；</li></ol> <blockquote><p>握手过程中传送的包里不包含数据，三次握手完毕后，客户端与服务器才正式开始传送数据。</p></blockquote> <h3 id="_2-tcp-四次挥手"><a href="#_2-tcp-四次挥手" class="header-anchor">#</a> 2. TCP 四次挥手</h3> <ol><li>Client 发送一个 FIN 包来告诉 Server 我已经没数据需要发给 Server 了；</li> <li>Server 收到后回复一个 ACK 确认包说我知道了；</li> <li>然后 server 在自己也没数据发送给 client 后，Server 也发送一个 FIN 包给 Client 告诉 Client 我也已经没数据发给 client 了；</li> <li>Client 收到后，就会回复一个 ACK 确认包说我知道了。</li></ol> <h3 id="_3-tcp-ip如何保证数据包传输的有序可靠"><a href="#_3-tcp-ip如何保证数据包传输的有序可靠" class="header-anchor">#</a> 3. TCP/IP如何保证数据包传输的有序可靠</h3> <p>对字节流分段并进行编号然后<code>通过 ACK 回复</code>和<code>超时重发</code>这两个机制来保证。</p> <p>（1）为了保证数据包的可靠传递，发送方必须把已发送的数据包保留在缓冲区；
（2）并为每个已发送的数据包启动一个超时定时器；
（3）如在定时器超时之前收到了对方发来的应答信息（可能是对本包的应答，也可以是对本包后续包的应答），则释放该数据包占用的缓冲区;
（4）否则，重传该数据包，直到收到应答或重传次数超过规定的最大次数为止。
（5）接收方收到数据包后，先进行CRC校验，如果正确则把数据交给上层协议，然后给发送方发送一个累计应答包，表明该数据已收到，如果接收方正好也有数据要发给发送方，应答包也可方在数据包中捎带过去。</p> <h3 id="_4-tcp和udp的区别"><a href="#_4-tcp和udp的区别" class="header-anchor">#</a> 4. TCP和UDP的区别</h3> <ol><li>TCP是面向<code>链接</code>的，而UDP是面向无连接的。</li> <li>TCP仅支持<code>单播传输</code>，UDP 提供了单播，多播，广播的功能。</li> <li>TCP的三次握手保证了连接的<code>可靠性</code>; UDP是无连接的、不可靠的一种数据传输协议，首先不可靠性体现在无连接上，通信都不需要建立连接，对接收到的数据也不发送确认信号，发送端不知道数据是否会正确接收。</li> <li>UDP的<code>头部开销</code>比TCP的更小，数据<code>传输速率更高</code>，<code>实时性更好</code>。</li></ol> <p>传送门 ☞ <a href="https://juejin.cn/post/6992743999756845087" target="_blank" rel="noopener noreferrer"># 深度剖析TCP与UDP的区别<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <h3 id="_5-tcp粘包问题分析与对策"><a href="#_5-tcp粘包问题分析与对策" class="header-anchor">#</a> 5. TCP粘包问题分析与对策</h3> <p>TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包，从接收缓冲区看，后一包数据的头紧接着前一包数据的尾。</p> <p><strong>粘包出现原因</strong></p> <p>简单得说，在流传输中出现，UDP不会出现粘包，因为它有<strong>消息边界</strong></p> <p>粘包情况有两种，一种是<code>粘在一起的包都是完整的数据包</code>，另一种情况是<code>粘在一起的包有不完整的包</code>。</p> <p>为了<strong>避免粘包</strong>现象，可采取以下几种措施：</p> <p>（1）对于发送方引起的粘包现象，用户可通过编程设置来避免，<code>TCP提供了强制数据立即传送的操作指令push</code>，TCP软件收到该操作指令后，就立即将本段数据发送出去，而不必等待发送缓冲区满；</p> <p>（2）对于接收方引起的粘包，则可通过优化程序设计、精简接收进程工作量、<code>提高接收进程优先级等措施</code>，使其及时接收数据，从而尽量避免出现粘包现象；</p> <p>（3）由接收方控制，将一包数据按结构字段，人为控制分多次接收，然后合并，通过这种手段来避免粘包。<code>分包多发</code>。</p> <p>以上提到的三种措施，都有其不足之处。</p> <p>（1）第一种编程设置方法虽然可以避免发送方引起的粘包，但它关闭了优化算法，降低了网络发送效率，影响应用程序的性能，一般不建议使用。</p> <p>（2）第二种方法只能减少出现粘包的可能性，但并不能完全避免粘包，当发送频率较高时，或由于网络突发可能使某个时间段数据包到达接收方较快，接收方还是有可能来不及接收，从而导致粘包。</p> <p>（3）第三种方法虽然避免了粘包，但应用程序的效率较低，对实时应用的场合不适合。</p> <blockquote><p>一种比较周全的对策是：接收方创建一预处理线程，对接收到的数据包进行预处理，将粘连的包分开。实验证明这种方法是高效可行的。</p></blockquote> <h2 id="http-请求跨域问题"><a href="#http-请求跨域问题" class="header-anchor">#</a> HTTP 请求跨域问题</h2> <h3 id="_1-跨域的原理"><a href="#_1-跨域的原理" class="header-anchor">#</a> 1. 跨域的原理</h3> <p><strong>跨域</strong>，是指浏览器不能执行其他网站的脚本。它是由浏览器的<code>同源策略</code>造成的。
<strong>同源策略</strong>,是浏览器对 JavaScript 实施的安全限制，只要<code>协议、域名、端口</code>有任何一个不同，都被当作是不同的域。
<strong>跨域原理</strong>，即是通过各种方式，<code>避开浏览器的安全限制</code>。</p> <h3 id="_2-解决方案"><a href="#_2-解决方案" class="header-anchor">#</a> 2. 解决方案</h3> <p>最初做项目的时候，使用的是jsonp，但存在一些问题，使用get请求不安全，携带数据较小，后来也用过iframe，但只有主域相同才行，也是存在些问题，后来通过了解和学习发现使用代理和proxy代理配合起来使用比较方便，就引导后台按这种方式做下服务器配置，在开发中使用proxy，在服务器上使用nginx代理，这样开发过程中彼此都方便，效率也高；现在h5新特性还有 windows.postMessage()</p> <ul><li><p><strong>JSONP</strong>：
ajax 请求受同源策略影响，不允许进行跨域请求，而 script 标签 src 属性中的链 接却可以访问跨域的 js 脚本，利用这个特性，服务端不再返回 JSON 格式的数据，而是 返回一段调用某个函数的 js 代码，在 src 中进行了调用，这样实现了跨域。</p> <p>步骤：</p> <ol><li>去创建一个script标签</li> <li>script的src属性设置接口地址</li> <li>接口参数，必须要带一个自定义函数名，要不然后台无法返回数据</li> <li>通过定义函数名去接受返回的数据</li></ol> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">//动态创建 script</span>
<span class="token keyword">var</span> script <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'script'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 设置回调函数</span>
<span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">//设置 script 的 src 属性，并设置请求地址</span>
script<span class="token punctuation">.</span>src <span class="token operator">=</span> <span class="token string">'http://localhost:3000/?callback=getData'</span><span class="token punctuation">;</span>

<span class="token comment">// 让 script 生效</span>
document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>script<span class="token punctuation">)</span><span class="token punctuation">;</span>
复制代码
</code></pre></div><p><strong>JSONP 的缺点</strong>:
JSON 只支持 get，因为 script 标签只能使用 get 请求； JSONP 需要后端配合返回指定格式的数据。</p></li> <li><p><strong>document.domain</strong> 基础域名相同 子域名不同</p></li> <li><p><strong>window.name</strong> 利用在一个浏览器窗口内，载入所有的域名都是共享一个window.name</p></li> <li><p><strong>CORS</strong> CORS(Cross-origin resource sharing)跨域资源共享 服务器设置对CORS的支持原理：服务器设置Access-Control-Allow-Origin HTTP响应头之后，浏览器将会允许跨域请求</p></li> <li><p><strong>proxy代理</strong> 目前常用方式,通过服务器设置代理</p></li> <li><p><strong>window.postMessage()</strong> 利用h5新特性window.postMessage()</p></li></ul> <h2 id="本地存储"><a href="#本地存储" class="header-anchor">#</a> 本地存储</h2> <p>有Cookie、sessionStorage、localStorage</p> <p><strong>相同点</strong>：</p> <ul><li>存储在客户端</li></ul> <p><strong>不同点</strong>：</p> <ul><li>cookie数据大小不能超过4k；sessionStorage和localStorage的存储比cookie大得多，可以达到5M+</li> <li>cookie设置的过期时间之前一直有效；localStorage永久存储，浏览器关闭后数据不丢失除非主动删除数据；sessionStorage数据在当前浏览器窗口关闭后自动删除</li> <li>cookie的数据会自动的传递到服务器；sessionStorage和localStorage数据保存在本地</li></ul> <h2 id="浏览器从输入url到页面加载的全过程"><a href="#浏览器从输入url到页面加载的全过程" class="header-anchor">#</a> 浏览器从输入URL到页面加载的全过程</h2> <p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e44aa8a92602405db3c12161b71e2094~tplv-k3u1fbpfcp-watermark.awebp" alt="从输入URL到页面加载的主干流程"></p> <ol><li><p>首先在浏览器中输入URL</p></li> <li><p>查找缓存：浏览器先查看浏览器缓存-系统缓存-路由缓存中是否有该地址页面，如果有则显示页面内容。如果没有则进行下一步。</p> <ul><li>浏览器缓存：浏览器会记录DNS一段时间，因此，只是第一个地方解析DNS请求；</li> <li>操作系统缓存:如果在浏览器缓存中不包含这个记录，则会使系统调用操作系统， 获取操作系统的记录(保存最近的DNS查询缓存)；</li> <li>路由器缓存：如果上述两个步骤均不能成功获取DNS记录，继续搜索路由器缓存；</li> <li>ISP缓存：若上述均失败，继续向ISP搜索。</li></ul></li> <li><p>DNS域名解析：浏览器向DNS服务器发起请求，解析该URL中的域名对应的IP地址。<code>DNS服务器是基于UDP的，因此会用到UDP协议。</code>。</p></li> <li><p>建立TCP连接：解析出IP地址后，根据IP地址和默认80端口，和服务器建立TCP连接</p></li> <li><p>发起HTTP请求：浏览器发起读取文件的HTTP请求，，该请求报文作为TCP三次握手的第三次数据发送给服务器</p></li> <li><p>服务器响应请求并返回结果：服务器对浏览器请求做出响应，并把对应的html文件发送给浏览器</p></li> <li><p>关闭TCP连接：通过四次挥手释放TCP连接</p></li> <li><p>浏览器渲染：客户端（浏览器）解析HTML内容并渲染出来，浏览器接收到数据包后的解析流程为：</p> <ul><li>构建DOM树：词法分析然后解析成DOM树（dom tree），是由dom元素及属性节点组成，树的根是document对象</li> <li>构建CSS规则树：生成CSS规则树（CSS Rule Tree）</li> <li>构建render树：Web浏览器将DOM和CSSOM结合，并构建出渲染树（render tree）</li> <li>布局（Layout）：计算出每个节点在屏幕中的位置</li> <li>绘制（Painting）：即遍历render树，并使用UI后端层绘制每个节点。</li></ul> <p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a90660027f0d4c559732519bad4c6323~tplv-k3u1fbpfcp-watermark.awebp" alt="浏览器渲染流程图"></p></li> <li><p>JS引擎解析过程：调用JS引擎执行JS代码（JS的解释阶段，预处理阶段，执行阶段生成执行上下文，VO，作用域链、回收机制等等）</p> <ul><li>创建window对象：window对象也叫全局执行环境，当页面产生时就被创建，所有的全局变量和函数都属于window的属性和方法，而DOM Tree也会映射在window的doucment对象上。当关闭网页或者关闭浏览器时，全局执行环境会被销毁。</li> <li>加载文件：完成js引擎分析它的语法与词法是否合法，如果合法进入预编译</li> <li>预编译：在预编译的过程中，浏览器会寻找全局变量声明，把它作为window的属性加入到window对象中，并给变量赋值为'undefined'；寻找全局函数声明，把它作为window的方法加入到window对象中，并将函数体赋值给他（匿名函数是不参与预编译的，因为它是变量）。而变量提升作为不合理的地方在ES6中已经解决了，函数提升还存在。</li> <li>解释执行：执行到变量就赋值，如果变量没有被定义，也就没有被预编译直接赋值，在ES5非严格模式下这个变量会成为window的一个属性，也就是成为全局变量。string、int这样的值就是直接把值放在变量的存储空间里，object对象就是把指针指向变量的存储空间。函数执行，就将函数的环境推入一个环境的栈中，执行完成后再弹出，控制权交还给之前的环境。JS作用域其实就是这样的执行流机制实现的。</li></ul></li></ol> <h2 id="重排和重绘"><a href="#重排和重绘" class="header-anchor">#</a> 重排和重绘</h2> <h3 id="_1-浏览器重绘与重排的区别"><a href="#_1-浏览器重绘与重排的区别" class="header-anchor">#</a> 1 浏览器重绘与重排的区别？</h3> <ul><li><code>重排/回流（Reflow）</code>：当<code>DOM</code>的变化影响了元素的几何信息，浏览器需要重新计算元素的几何属性，将其安放在界面中的正确位置，这个过程叫做重排。表现为重新生成布局，重新排列元素。</li> <li><code>重绘(Repaint)</code>: 当一个元素的外观发生改变，但没有改变布局,重新把元素外观绘制出来的过程，叫做重绘。表现为某些元素的外观被改变</li></ul> <p>单单改变元素的外观，肯定不会引起网页重新生成布局，但当浏览器完成重排之后，将会重新绘制受到此次重排影响的部分</p> <p>重排和重绘代价是高昂的，它们会破坏用户体验，并且让UI展示非常迟缓，而相比之下重排的性能影响更大，在两者无法避免的情况下，一般我们宁可选择代价更小的重绘。</p> <p>『重绘』不一定会出现『重排』，『重排』必然会出现『重绘』。</p> <h3 id="_2-如何触发重排和重绘"><a href="#_2-如何触发重排和重绘" class="header-anchor">#</a> 2 如何触发重排和重绘？</h3> <p>任何改变用来构建渲染树的信息都会导致一次重排或重绘：</p> <ul><li>添加、删除、更新DOM节点</li> <li>通过display: none隐藏一个DOM节点-触发重排和重绘</li> <li>通过visibility: hidden隐藏一个DOM节点-只触发重绘，因为没有几何变化</li> <li>移动或者给页面中的DOM节点添加动画</li> <li>添加一个样式表，调整样式属性</li> <li>用户行为，例如调整窗口大小，改变字号，或者滚动。</li></ul> <h3 id="_3-如何避免重绘或者重排"><a href="#_3-如何避免重绘或者重排" class="header-anchor">#</a> 3 如何避免重绘或者重排？</h3> <ol><li><p><code>集中改变样式</code>，不要一条一条地修改 DOM 的样式。</p></li> <li><p>不要把 DOM 结点的属性值放在循环里当成循环里的变量。</p></li> <li><p>为动画的 HTML 元件使用 <code>fixed</code> 或 <code>absoult</code> 的 <code>position</code>，那么修改他们的 CSS 是不会 reflow 的。</p></li> <li><p>不使用 table 布局。因为可能很小的一个小改动会造成整个 table 的重新布局。</p></li> <li><p>尽量只修改<code>position：absolute</code>或<code>fixed</code>元素，对其他元素影响不大</p></li> <li><p>动画开始<code>GPU</code>加速，<code>translate</code>使用<code>3D</code>变化</p></li> <li><p>提升为合成层</p> <p>将元素提升为合成层有以下优点：</p> <ul><li>合成层的位图，会交由 GPU 合成，比 CPU 处理要快</li> <li>当需要 repaint 时，只需要 repaint 本身，不会影响到其他的层</li> <li>对于 transform 和 opacity 效果，不会触发 layout 和 paint</li></ul> <p>提升合成层的最好方式是使用 CSS 的 will-change 属性：</p> <div class="language- extra-class"><pre class="language-text"><code>#target {
  will-change: transform;
}
复制代码
</code></pre></div><blockquote><p>关于合成层的详解请移步<a href="https://link.juejin.cn?target=http%3A%2F%2Ftaobaofed.org%2Fblog%2F2016%2F04%2F25%2Fperformance-composite%2F" target="_blank" rel="noopener noreferrer">无线性能优化：Composite<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote></li></ol> <h2 id="介绍下304过程"><a href="#介绍下304过程" class="header-anchor">#</a> 介绍下304过程</h2> <ul><li>a. 浏览器请求资源时首先命中资源的Expires 和 Cache-Control，Expires 受限于本地时间，如果修改了本地时间，可能会造成缓存失效，可以通过Cache-control: max-age指定最大生命周期，状态仍然返回200，但不会请求数据，在浏览器中能明显看到from cache字样。</li> <li>b. 强缓存失效，进入协商缓存阶段，首先验证ETagETag可以保证每一个资源是唯一的，资源变化都会导致ETag变化。服务器根据客户端上送的If-None-Match值来判断是否命中缓存。</li> <li>c. 协商缓存Last-Modify/If-Modify-Since阶段，客户端第一次请求资源时，服务服返回的header中会加上Last-Modify，Last-modify是一个时间标识该资源的最后修改时间。再次请求该资源时，request的请求头中会包含If-Modify-Since，该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后，根据资源的最后修改时间判断是否命中缓存。</li></ul> <h2 id="浏览器缓存机制-强制缓存-协商缓存"><a href="#浏览器缓存机制-强制缓存-协商缓存" class="header-anchor">#</a> 浏览器缓存机制 强制缓存 &amp;&amp; 协商缓存</h2> <p>浏览器与服务器通信的方式为应答模式，即是：浏览器发起HTTP请求 – 服务器响应该请求。那么浏览器第一次向服务器发起该请求后拿到请求结果，会根据响应报文中HTTP头的缓存标识，决定是否缓存结果，是则将请求结果和缓存标识存入浏览器缓存中，简单的过程如下图：</p> <p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/487144abaada4b9a8b34bc9375191ec7~tplv-k3u1fbpfcp-watermark.awebp" alt="图片"></p> <p>由上图我们可以知道：</p> <ul><li>浏览器每次发起请求，都会<code>先在浏览器缓存中查找该请求的结果以及缓存标识</code></li> <li>浏览器每次拿到返回的请求结果都会<code>将该结果和缓存标识存入浏览器缓存中</code></li></ul> <p>以上两点结论就是浏览器缓存机制的关键，他确保了每个请求的缓存存入与读取，只要我们再理解浏览器缓存的使用规则，那么所有的问题就迎刃而解了。为了方便理解，这里根据是否需要向服务器重新发起HTTP请求将缓存过程分为两个部分，分别是<code>强制缓存</code>和<code>协商缓存</code>。</p> <ul><li><p><strong>强制缓存</strong></p> <p><code>强制缓存就是向浏览器缓存查找该请求结果，并根据该结果的缓存规则来决定是否使用该缓存结果的过程。</code>当浏览器向服务器发起请求时，服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一起返回给浏览器，控制强制缓存的字段分别是 <code>Expires</code> 和 <code>Cache-Control</code>，其中Cache-Control优先级比Expires高。</p> <p>强制缓存的情况主要有三种(暂不分析协商缓存过程)，如下：</p> <ol><li>不存在该缓存结果和缓存标识，强制缓存失效，则直接向服务器发起请求（跟第一次发起请求一致）。</li> <li>存在该缓存结果和缓存标识，但该结果已失效，强制缓存失效，则使用协商缓存。</li> <li>存在该缓存结果和缓存标识，且该结果尚未失效，强制缓存生效，直接返回该结果</li></ol></li> <li><p><strong>协商缓存</strong></p> <p><code>协商缓存就是强制缓存失效后，浏览器携带缓存标识向服务器发起请求，由服务器根据缓存标识决定是否使用缓存的过程</code>，同样，协商缓存的标识也是在响应报文的HTTP头中和请求结果一起返回给浏览器的，控制协商缓存的字段分别有：<code>Last-Modified / If-Modified-Since</code> 和 <code>Etag / If-None-Match</code>，其中Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高。协商缓存主要有以下两种情况：</p> <ol><li>协商缓存生效，返回304</li> <li>协商缓存失效，返回200和请求结果结果</li></ol></li></ul> <p>传送门 ☞ <a href="https://juejin.cn/post/6992843117963509791" target="_blank" rel="noopener noreferrer"># 彻底理解浏览器的缓存机制<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <h2 id="进程、线程和协程"><a href="#进程、线程和协程" class="header-anchor">#</a> 进程、线程和协程</h2> <p><strong>进程</strong>是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程，<code>是操作系统进行资源分配和调度的一个独立单位</code>，是应用程序运行的载体。进程是一种抽象的概念，从来没有统一的标准定义。</p> <p><strong>线程</strong>是程序执行中一个单一的顺序控制流程，是<code>程序执行流的最小单元</code>，是处理器调度和分派的基本单位。一个进程可以有一个或多个线程，各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。一个标准的线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成。而进程由内存空间(代码、数据、进程空间、打开的文件)和一个或多个线程组成。</p> <p><strong>协程</strong>，英文Coroutines，是一种<code>基于线程之上，但又比线程更加轻量级的存在</code>，这种由程序员自己写程序来管理的轻量级线程叫做『用户空间线程』，具有对内核来说不可见的特性。</p> <p><strong>进程和线程的区别与联系</strong></p> <p>【区别】：</p> <p>调度：线程作为调度和分配的基本单位，进程作为拥有资源的基本单位；</p> <p>并发性：不仅进程之间可以并发执行，同一个进程的多个线程之间也可并发执行；</p> <p>拥有资源：进程是拥有资源的一个独立单位，线程不拥有系统资源，但可以访问隶属于进程的资源。</p> <p>系统开销：在创建或撤消进程时，由于系统都要为之分配和回收资源，导致系统的开销明显大于创建或撤消线程时的开销。但是进程有独立的地址空间，一个进程崩溃后，在保护模式下不会对其它进程产生影响，而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量，但线程之间没有单独的地址空间，一个进程死掉就等于所有的线程死掉，所以多进程的程序要比多线程的程序健壮，但在进程切换时，耗费资源较大，效率要差一些。</p> <p>【联系】：</p> <p>一个线程只能属于一个进程，而一个进程可以有多个线程，但至少有一个线程；</p> <p>资源分配给进程，同一进程的所有线程共享该进程的所有资源；</p> <p>处理机分给线程，即真正在处理机上运行的是线程；</p> <p>线程在执行过程中，需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。</p> <p><a href="https://link.juejin.cn?target=http%3A%2F%2Fwww.360doc.com%2Fcontent%2F20%2F0417%2F14%2F32196507_906628857.shtml" target="_blank" rel="noopener noreferrer">☞了解更多<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <h2 id="html5-新特性、语义化"><a href="#html5-新特性、语义化" class="header-anchor">#</a> HTML5 新特性、语义化</h2> <ol><li><p><strong>概念</strong>：</p> <p>HTML5的语义化指的是<code>合理正确的使用语义化的标签来创建页面结构</code>。【正确的标签做正确的事】</p></li> <li><p><strong>语义化标签</strong>：</p> <p>header nav main article section aside footer</p></li> <li><p><strong>语义化的优点</strong>:</p> <ul><li>在<code>没CSS样式的情况下，页面整体也会呈现很好的结构效果</code></li> <li><code>代码结构清晰</code>，易于阅读，</li> <li><code>利于开发和维护</code> 方便其他设备解析（如屏幕阅读器）根据语义渲染网页。</li> <li><code>有利于搜索引擎优化（SEO）</code>，搜索引擎爬虫会根据不同的标签来赋予不同的权重</li></ul></li></ol> <h2 id="css-选择器及优先级"><a href="#css-选择器及优先级" class="header-anchor">#</a> CSS 选择器及优先级</h2> <p><strong>选择器</strong></p> <ul><li>id选择器(#myid)</li> <li>类选择器(.myclass)</li> <li>属性选择器(a[rel=&quot;external&quot;])</li> <li>伪类选择器(a:hover, li:nth-child)</li> <li>标签选择器(div, h1,p)</li> <li>相邻选择器（h1 + p）</li> <li>子选择器(ul &gt; li)</li> <li>后代选择器(li a)</li> <li>通配符选择器(*)</li></ul> <p><strong>优先级：</strong></p> <ul><li><code>!important</code></li> <li>内联样式（1000）</li> <li>ID选择器（0100）</li> <li>类选择器/属性选择器/伪类选择器（0010）</li> <li>元素选择器/伪元素选择器（0001）</li> <li>关系选择器/通配符选择器（0000）</li></ul> <p>带!important 标记的样式属性优先级最高； 样式表的来源相同时：<code>!important &gt; 行内样式&gt;ID选择器 &gt; 类选择器 &gt; 标签 &gt; 通配符 &gt; 继承 &gt; 浏览器默认属性</code></p> <h2 id="position-属性的值有哪些及其区别"><a href="#position-属性的值有哪些及其区别" class="header-anchor">#</a> position 属性的值有哪些及其区别</h2> <p><strong>固定定位 fixed</strong>： 元素的位置相对于浏览器窗口是固定位置，即使窗口是滚动的它也不会移动。Fixed 定 位使元素的位置与文档流无关，因此不占据空间。 Fixed 定位的元素和其他元素重叠。</p> <p><strong>相对定位 relative</strong>： 如果对一个元素进行相对定位，它将出现在它所在的位置上。然后，可以通过设置垂直 或水平位置，让这个元素“相对于”它的起点进行移动。 在使用相对定位时，无论是 否进行移动，元素仍然占据原来的空间。因此，移动元素会导致它覆盖其它框。</p> <p><strong>绝对定位 absolute</strong>： 绝对定位的元素的位置相对于最近的已定位父元素，如果元素没有已定位的父元素，那 么它的位置相对于。absolute 定位使元素的位置与文档流无关，因此不占据空间。 absolute 定位的元素和其他元素重叠。</p> <p><strong>粘性定位 sticky</strong>： 元素先按照普通文档流定位，然后相对于该元素在流中的 flow root（BFC）和 containing block（最近的块级祖先元素）定位。而后，元素定位表现为在跨越特定阈值前为相对定 位，之后为固定定位。</p> <p><strong>默认定位 Static</strong>： 默认值。没有定位，元素出现在正常的流中（忽略 top, bottom, left, right 或者 z-index 声 明）。 inherit: 规定应该从父元素继承 position 属性的值。</p> <h2 id="box-sizing属性"><a href="#box-sizing属性" class="header-anchor">#</a> box-sizing属性</h2> <p>box-sizing 规定两个并排的带边框的框，语法为 box-sizing：content-box/border-box/inherit</p> <p><strong>content-box</strong>：宽度和高度分别应用到元素的内容框，在宽度和高度之外绘制元素的内边距和边框。【标准盒子模型】</p> <p><strong>border-box</strong>：为元素设定的宽度和高度决定了元素的边框盒。【IE 盒子模型】</p> <p><strong>inherit</strong>：继承父元素的 box-sizing 值。</p> <h2 id="css-盒子模型"><a href="#css-盒子模型" class="header-anchor">#</a> CSS 盒子模型</h2> <p>CSS 盒模型本质上是一个盒子，它包括：边距，边框，填充和实际内容。CSS 中的盒子模型包括 IE 盒子模型和标准的 W3C 盒子模型。
在标准的盒子模型中，<code>width 指 content 部分的宽度</code>。
在 IE 盒子模型中，<code>width 表示 content+padding+border 这三个部分的宽度</code>。</p> <p>故在计算盒子的宽度时存在差异：</p> <p><strong>标准盒模型：</strong> 一个块的总宽度 = width+margin(左右)+padding(左右)+border(左右)</p> <p><strong>怪异盒模型：</strong> 一个块的总宽度 = width+margin（左右）（既 width 已经包含了 padding 和 border 值）</p> <h2 id="bfc-块级格式上下文"><a href="#bfc-块级格式上下文" class="header-anchor">#</a> BFC（块级格式上下文）</h2> <p><strong>BFC的概念</strong></p> <p><code>BFC</code> 是 <code>Block Formatting Context</code>的缩写，即块级格式化上下文。<code>BFC</code>是CSS布局的一个概念，是一个独立的渲染区域，规定了内部box如何布局， 并且这个区域的子元素不会影响到外面的元素，其中比较重要的布局规则有内部 box 垂直放置，计算 BFC 的高度的时候，浮动元素也参与计算。</p> <p><strong>BFC的原理布局规则</strong></p> <ul><li>内部的Box会在<code>垂直方向</code>，一个接一个地放置</li> <li>Box<code>垂直方向的距离由margin决定</code>。属于同一个BFC的两个相邻Box的margin会发生重叠</li> <li>每个元素的margin box的左边， 与包含块border box的左边相接触(对于从左往右的格式化，否则相反</li> <li>BFC的区域<code>不会与float box重叠</code></li> <li>BFC是一个独立容器，容器里面的<code>子元素不会影响到外面的元素</code></li> <li>计算BFC的高度时，<code>浮动元素也参与计算高度</code></li> <li>元素的类型和<code>display属性，决定了这个Box的类型</code>。不同类型的Box会参与不同的<code>Formatting Context</code>。</li></ul> <p><strong>如何创建BFC？</strong></p> <ul><li>根元素，即HTML元素</li> <li>float的值不为none</li> <li>position为absolute或fixed</li> <li>display的值为inline-block、table-cell、table-caption</li> <li>overflow的值不为visible</li></ul> <p><strong>BFC的使用场景</strong></p> <ul><li>去除边距重叠现象</li> <li>清除浮动（让父元素的高度包含子浮动元素）</li> <li>避免某元素被浮动元素覆盖</li> <li>避免多列布局由于宽度计算四舍五入而自动换行</li></ul> <h2 id="让一个元素水平垂直居中"><a href="#让一个元素水平垂直居中" class="header-anchor">#</a> 让一个元素水平垂直居中</h2> <ul><li><p><strong>水平居中</strong></p> <ul><li><p>对于 行内元素 : <code>text-align: center</code>;</p></li> <li><p>对于确定宽度的块级元素：</p> <p>（1）width和margin实现。<code>margin: 0 auto</code>;</p> <p>（2）绝对定位和margin-left: -width/2, 前提是父元素position: relative</p></li> <li><p>对于宽度未知的块级元素</p> <p>（1）<code>table标签配合margin左右auto实现水平居中</code>。使用table标签（或直接将块级元素设值为 display:table），再通过给该标签添加左右margin为auto。</p> <p>（2）inline-block实现水平居中方法。display：inline-block和text-align:center实现水平居中。</p> <p>（3）<code>绝对定位+transform</code>，translateX可以移动本身元素的50%。</p> <p>（4）flex布局使用<code>justify-content:center</code></p></li></ul></li> <li><p><strong>垂直居中</strong></p> <ol><li>利用 <code>line-height</code> 实现居中，这种方法适合纯文字类</li> <li>通过设置父容器 相对定位 ，子级设置 <code>绝对定位</code>，标签通过margin实现自适应居中</li> <li>弹性布局 flex :父级设置display: flex; 子级设置margin为auto实现自适应居中</li> <li>父级设置相对定位，子级设置绝对定位，并且通过位移 transform 实现</li> <li><code>table 布局</code>，父级通过转换成表格形式，<code>然后子级设置 vertical-align 实现</code>。（需要注意的是：vertical-align: middle使用的前提条件是内联元素以及display值为table-cell的元素）。</li></ol></li></ul> <p>传送门 ☞ <a href="https://juejin.cn/post/7008348524530106381" target="_blank" rel="noopener noreferrer"># 图解CSS水平垂直居中常见面试方法<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <h2 id="隐藏页面中某个元素的方法"><a href="#隐藏页面中某个元素的方法" class="header-anchor">#</a> 隐藏页面中某个元素的方法</h2> <p>1.<code>opacity：0</code>，该元素隐藏起来了，但不会改变页面布局，并且，如果该元素已经绑定 一些事件，如click 事件，那么点击该区域，也能触发点击事件的</p> <p>2.<code>visibility：hidden</code>，该元素隐藏起来了，但不会改变页面布局，但是不会触发该元素已 经绑定的事件 ，隐藏对应元素，在文档布局中仍保留原来的空间（重绘）</p> <p>3.<code>display：none</code>，把元素隐藏起来，并且会改变页面布局，可以理解成在页面中把该元素。 不显示对应的元素，在文档布局中不再分配空间（回流+重绘）</p> <blockquote><p>该问题会引出 回流和重绘</p></blockquote> <h2 id="用css实现三角符号"><a href="#用css实现三角符号" class="header-anchor">#</a> 用CSS实现三角符号</h2> <div class="language-css extra-class"><pre class="language-css"><code><span class="token comment">/*记忆口诀：盒子宽高均为零，三面边框皆透明。 */</span>
<span class="token selector">div:after</span><span class="token punctuation">{</span>
    <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
    <span class="token property">width</span><span class="token punctuation">:</span> 0px<span class="token punctuation">;</span>
    <span class="token property">height</span><span class="token punctuation">:</span> 0px<span class="token punctuation">;</span>
    <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">&quot; &quot;</span><span class="token punctuation">;</span>
    <span class="token property">border-right</span><span class="token punctuation">:</span> 100px solid transparent<span class="token punctuation">;</span>
    <span class="token property">border-top</span><span class="token punctuation">:</span> 100px solid #ff0<span class="token punctuation">;</span>
    <span class="token property">border-left</span><span class="token punctuation">:</span> 100px solid transparent<span class="token punctuation">;</span>
    <span class="token property">border-bottom</span><span class="token punctuation">:</span> 100px solid transparent<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
复制代码
</code></pre></div><h2 id="页面布局"><a href="#页面布局" class="header-anchor">#</a> 页面布局</h2> <h3 id="_1-flex-布局"><a href="#_1-flex-布局" class="header-anchor">#</a> 1. Flex 布局</h3> <p>布局的传统解决方案，基于盒状模型，依赖 display 属性 + position 属性 + float 属性。它对于那些特殊布局非常不方便，比如，垂直居中就不容易实现。</p> <p>Flex 是 Flexible Box 的缩写，意为&quot;弹性布局&quot;,用来为盒状模型提供最大的灵活性。指定容器 display: flex 即可。 简单的分为容器属性和元素属性。</p> <p>容器的属性：</p> <ul><li>flex-direction：决定主轴的方向（即子 item 的排列方法）flex-direction: row | row-reverse | column | column-reverse;</li> <li>flex-wrap：决定换行规则 flex-wrap: nowrap | wrap | wrap-reverse;</li> <li>flex-flow： .box { flex-flow: || ; }</li> <li>justify-content：对其方式，水平主轴对齐方式</li> <li>align-items：对齐方式，竖直轴线方向</li> <li>align-content</li></ul> <p>项目的属性（元素的属性）：</p> <ul><li>order 属性：定义项目的排列顺序，顺序越小，排列越靠前，默认为 0</li> <li>flex-grow 属性：定义项目的放大比例，即使存在空间，也不会放大</li> <li>flex-shrink 属性：定义了项目的缩小比例，当空间不足的情况下会等比例的缩小，如果 定义个 item 的 flow-shrink 为 0，则为不缩小</li> <li>flex-basis 属性：定义了在分配多余的空间，项目占据的空间。</li> <li>flex：是 flex-grow 和 flex-shrink、flex-basis 的简写，默认值为 0 1 auto。</li> <li>align-self：允许单个项目与其他项目不一样的对齐方式，可以覆盖</li> <li>align-items，默认属 性为 auto，表示继承父元素的 align-items 比如说，用 flex 实现圣杯布局</li></ul> <h3 id="_2-rem-布局"><a href="#_2-rem-布局" class="header-anchor">#</a> 2. Rem 布局</h3> <p>首先 Rem 相对于根(html)的 font-size 大小来计算。简单的说它就是一个相对单例 如:font-size:10px;,那么（1rem = 10px）了解计算原理后首先解决怎么在不同设备上设置 html 的 font-size 大小。其实 rem 布局的本质是等比缩放，一般是基于宽度。</p> <p><strong>优点</strong>：可以快速适用移动端布局，字体，图片高度</p> <p><strong>缺点</strong>：</p> <p>①目前 ie 不支持，对 pc 页面来讲使用次数不多；
②数据量大：所有的图片，盒子都需要我们去给一个准确的值；才能保证不同机型的适配；
③在响应式布局中，必须通过 js 来动态控制根元素 font-size 的大小。也就是说 css 样式和 js 代码有一定的耦合性。且必须将改变 font-size 的代码放在 css 样式之前。</p> <h3 id="_3-百分比布局"><a href="#_3-百分比布局" class="header-anchor">#</a> 3. 百分比布局</h3> <p>通过百分比单位 &quot; % &quot; 来实现响应式的效果。通过百分比单位可以使得浏览器中的组件的宽和高随着浏览器的变化而变化，从而实现响应式的效果。 直观的理解，我们可能会认为子元素的百分比完全相对于直接父元素，height 百分比相 对于 height，width 百分比相对于 width。 padding、border、margin 等等不论是垂直方向还是水平方向，都相对于直接父元素的 width。 除了 border-radius 外，还有比如 translate、background-size 等都是相对于自身的。</p> <p><strong>缺点</strong>：</p> <p>（1）计算困难
（2）各个属性中如果使用百分比，相对父元素的属性并不是唯一的。造成我们使用百分比单位容易使布局问题变得复杂。</p> <h3 id="_4-浮动布局"><a href="#_4-浮动布局" class="header-anchor">#</a> 4. 浮动布局</h3> <p>浮动布局:当元素浮动以后可以向左或向右移动，直到它的外边缘碰到包含它的框或者另外一个浮动元素的边框为止。元素浮动以后会脱离正常的文档流，所以文档的普通流中的框就变的好像浮动元素不存在一样。</p> <p><strong>优点</strong></p> <p>这样做的优点就是在图文混排的时候可以很好的使文字环绕在图片周围。另外当元素浮动了起来之后，它有着块级元素的一些性质例如可以设置宽高等，但它与inline-block还是有一些区别的，第一个就是关于横向排序的时候，float可以设置方向而inline-block方向是固定的；还有一个就是inline-block在使用时有时会有空白间隙的问题</p> <p><strong>缺点</strong></p> <p>最明显的缺点就是浮动元素一旦脱离了文档流，就无法撑起父元素，<code>会造成父级元素高度塌陷</code>。</p> <h2 id="如何使用rem或viewport进行移动端适配"><a href="#如何使用rem或viewport进行移动端适配" class="header-anchor">#</a> 如何使用rem或viewport进行移动端适配</h2> <p><strong>rem适配原理：</strong></p> <p>改变了一个元素在不同设备上占据的css像素的个数</p> <p>rem适配的优缺点</p> <ul><li>优点：没有破坏完美视口</li> <li>缺点：px值转换rem太过于复杂(下面我们使用less来解决这个问题)</li></ul> <p><strong>viewport适配的原理</strong></p> <p>viewport适配方案中，每一个元素在不同设备上占据的css像素的个数是一样的。但是css像素和物理像素的比例是不一样的，等比的</p> <p>viewport适配的优缺点</p> <ul><li>在我们设计图上所量取的大小即为我们可以设置的像素大小，即所量即所设</li> <li>缺点破坏完美视口</li></ul> <h2 id="清除浮动的方式"><a href="#清除浮动的方式" class="header-anchor">#</a> 清除浮动的方式</h2> <ul><li>添加额外标签</li></ul> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>parent<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    //添加额外标签并且添加clear属性
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token value css language-css"><span class="token property">clear</span><span class="token punctuation">:</span>both</span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    //也可以加一个br标签
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
复制代码
</code></pre></div><ul><li>父级添加overflow属性，或者设置高度</li> <li>建立伪类选择器清除浮动</li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">//在css中添加:after伪元素</span>
<span class="token punctuation">.</span>parent<span class="token operator">:</span>after<span class="token punctuation">{</span>
    <span class="token comment">/* 设置添加子元素的内容是空 */</span>
    content<span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">;</span>
    <span class="token comment">/* 设置添加子元素为块级元素 */</span>
    display<span class="token operator">:</span> block<span class="token punctuation">;</span>
    <span class="token comment">/* 设置添加的子元素的高度0 */</span>
    height<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token comment">/* 设置添加子元素看不见 */</span>
    visibility<span class="token operator">:</span> hidden<span class="token punctuation">;</span>
    <span class="token comment">/* 设置clear：both */</span>
    clear<span class="token operator">:</span> both<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
复制代码
</code></pre></div><h2 id="js中的8种数据类型及区别"><a href="#js中的8种数据类型及区别" class="header-anchor">#</a> JS中的8种数据类型及区别</h2> <p>包括值类型(基本对象类型)和引用类型(复杂对象类型)</p> <p><strong>基本类型(值类型)：</strong> Number(数字),String(字符串),Boolean(布尔),Symbol(符号),null(空),undefined(未定义)在内存中占据固定大小，保存在栈内存中</p> <p><strong>引用类型(复杂数据类型)：</strong> Object(对象)、Function(函数)。其他还有Array(数组)、Date(日期)、RegExp(正则表达式)、特殊的基本包装类型(String、Number、Boolean) 以及单体内置对象(Global、Math)等 引用类型的值是对象 保存在堆内存中，栈内存存储的是对象的变量标识符以及对象在堆内存中的存储地址。</p> <h2 id="js中的数据类型检测方案"><a href="#js中的数据类型检测方案" class="header-anchor">#</a> JS中的数据类型检测方案</h2> <h3 id="_1-typeof"><a href="#_1-typeof" class="header-anchor">#</a> 1.typeof</h3> <div class="language-js extra-class"><pre class="language-js"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>               <span class="token comment">// number</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token comment">// boolean</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> <span class="token string">'mc'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token comment">// string</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token comment">// function</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>   <span class="token comment">// function</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>              <span class="token comment">// object </span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>              <span class="token comment">// object</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token comment">// object</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span><span class="token punctuation">;</span>       <span class="token comment">// undefined</span>
复制代码
</code></pre></div><p>优点：能够快速区分基本数据类型</p> <p>缺点：不能将Object、Array和Null区分，都返回object</p> <h3 id="_2-instanceof"><a href="#_2-instanceof" class="header-anchor">#</a> 2.instanceof</h3> <div class="language-js extra-class"><pre class="language-js"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token keyword">instanceof</span> <span class="token class-name">Number</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                    <span class="token comment">// false</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token boolean">true</span> <span class="token keyword">instanceof</span> <span class="token class-name">Boolean</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token comment">// false </span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'str'</span> <span class="token keyword">instanceof</span> <span class="token class-name">String</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token comment">// false  </span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token keyword">instanceof</span> <span class="token class-name">Array</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                    <span class="token comment">// true</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token keyword">instanceof</span> <span class="token class-name">Function</span><span class="token punctuation">)</span><span class="token punctuation">;</span>       <span class="token comment">// true</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token keyword">instanceof</span> <span class="token class-name">Object</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                   <span class="token comment">// true</span>
复制代码
</code></pre></div><p>优点：能够区分Array、Object和Function，适合用于判断自定义的类实例对象</p> <p>缺点：Number，Boolean，String基本数据类型不能判断</p> <h3 id="_3-object-prototype-tostring-call"><a href="#_3-object-prototype-tostring-call" class="header-anchor">#</a> 3.Object.prototype.toString.call()</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> toString <span class="token operator">=</span> <span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>toString<span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                      <span class="token comment">//[object Number]</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                   <span class="token comment">//[object Boolean]</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">'mc'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                   <span class="token comment">//[object String]</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                     <span class="token comment">//[object Array]</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                     <span class="token comment">//[object Object]</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>           <span class="token comment">//[object Function]</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">undefined</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>              <span class="token comment">//[object Undefined]</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                   <span class="token comment">//[object Null]</span>
复制代码
</code></pre></div><p>优点：精准判断数据类型</p> <p>缺点：写法繁琐不容易记，推荐进行封装后使用</p> <h2 id="var-let-const"><a href="#var-let-const" class="header-anchor">#</a> var &amp;&amp; let &amp;&amp; const</h2> <p>ES6之前创建变量用的是var,之后创建变量用的是let/const</p> <p><strong>三者区别</strong>：</p> <ol><li>var定义的变量，<code>没有块的概念，可以跨块访问</code>, 不能跨函数访问。
let定义的变量，只能在块作用域里访问，不能跨块访问，也不能跨函数访问。
const用来定义常量，使用时必须初始化(即必须赋值)，只能在块作用域里访问，且不能修改。</li> <li>var可以<code>先使用，后声明</code>，因为存在变量提升；let必须先声明后使用。</li> <li>var是允许在相同作用域内<code>重复声明同一个变量</code>的，而let与const不允许这一现象。</li> <li>在全局上下文中，基于let声明的全局变量和全局对象GO（window）没有任何关系 ;
var声明的变量会和GO有映射关系；</li> <li><code>会产生暂时性死区</code>：</li></ol> <blockquote><p>暂时性死区是浏览器的bug：检测一个未被声明的变量类型时，不会报错，会返回undefined
如：console.log(typeof a) //undefined
而：console.log(typeof a)//未声明之前不能使用
let a</p></blockquote> <ol><li>let /const/function会把当前所在的大括号(除函数之外)作为一个全新的块级上下文，应用这个机制，在开发项目的时候，遇到循环事件绑定等类似的需求，无需再自己构建闭包来存储，只要基于let的块作用特征即可解决</li></ol> <h2 id="js垃圾回收机制"><a href="#js垃圾回收机制" class="header-anchor">#</a> JS垃圾回收机制</h2> <ol><li><p>项目中，如果存在大量不被释放的内存（堆/栈/上下文），页面性能会变得很慢。当某些代码操作不能被合理释放，就会造成内存泄漏。我们尽可能减少使用闭包，因为它会消耗内存。</p></li> <li><p>浏览器垃圾回收机制/内存回收机制:</p> <blockquote><p>浏览器的<code>Javascript</code>具有自动垃圾回收机制(<code>GC:Garbage Collecation</code>)，垃圾收集器会定期（周期性）找出那些不在继续使用的变量，然后释放其内存。</p></blockquote> <p><strong>标记清除</strong>:在<code>js</code>中，最常用的垃圾回收机制是标记清除：当变量进入执行环境时，被标记为“进入环境”，当变量离开执行环境时，会被标记为“离开环境”。垃圾回收器会销毁那些带标记的值并回收它们所占用的内存空间。
<strong>谷歌浏览器</strong>：“查找引用”，浏览器不定时去查找当前内存的引用，如果没有被占用了，浏览器会回收它；如果被占用，就不能回收。
<strong>IE浏览器</strong>：“引用计数法”，当前内存被占用一次，计数累加1次，移除占用就减1，减到0时，浏览器就回收它。</p></li> <li><p>优化手段：内存优化 ; 手动释放：取消内存的占用即可。</p> <p>（1）堆内存：fn = null 【null：空指针对象】</p> <p>（2）栈内存：把上下文中，被外部占用的堆的占用取消即可。</p></li> <li><p>内存泄漏</p> <p>在 JS 中，常见的内存泄露主要有 4 种,全局变量、闭包、DOM 元素的引用、定时器</p></li></ol> <h2 id="作用域和作用域链"><a href="#作用域和作用域链" class="header-anchor">#</a> 作用域和作用域链</h2> <p>创建函数的时候，已经声明了当前函数的作用域==&gt;<code>当前创建函数所处的上下文</code>。如果是在全局下创建的函数就是<code>[[scope]]:EC(G)</code>，函数执行的时候，形成一个全新的私有上下文<code>EC(FN)</code>，供字符串代码执行(进栈执行)</p> <p>定义：简单来说作用域就是变量与函数的可访问范围，<code>由当前环境与上层环境的一系列变量对象组成</code>
1.全局作用域：代码在程序的任何地方都能被访问，window 对象的内置属性都拥有全局作用域。
2.函数作用域：在固定的代码片段才能被访问</p> <p>作用：作用域最大的用处就是<code>隔离变量</code>，不同作用域下同名变量不会有冲突。</p> <p><strong>作用域链参考链接</strong>一般情况下，变量到 创建该变量 的函数的作用域中取值。但是如果在当前作用域中没有查到，就会向上级作用域去查，直到查到全局作用域，这么一个查找过程形成的链条就叫做作用域链。</p> <h2 id="闭包的两大作用-保存-保护"><a href="#闭包的两大作用-保存-保护" class="header-anchor">#</a> 闭包的两大作用：保存/保护</h2> <ul><li><p><strong>闭包的概念</strong></p> <p>函数执行时形成的私有上下文EC(FN)，正常情况下，代码执行完会出栈后释放;但是特殊情况下，如果当前私有上下文中的某个东西被上下文以外的事物占用了，则上下文不会出栈释放，从而形成不销毁的上下文。 函数执行函数执行过程中，会形成一个全新的私有上下文，可能会被释放，可能不会被释放，不论释放与否，他的作用是：</p></li></ul> <p>（1）保护：划分一个独立的代码执行区域，在这个区域中有自己私有变量存储的空间，保护自己的私有变量不受外界干扰（操作自己的私有变量和外界没有关系）；</p> <p>（2）保存：如果当前上下文不被释放【只要上下文中的某个东西被外部占用即可】，则存储的这些私有变量也不会被释放，可以供其下级上下文中调取使用，相当于把一些值保存起来了；</p> <p>我们把函数执行形成私有上下文，来保护和保存私有变量机制称为<code>闭包</code>。</p> <blockquote><p>闭包是指有权访问另一个函数作用域中的变量的函数--《JavaScript高级程序设计》</p></blockquote> <p><strong>稍全面的回答</strong>： 在js中变量的作用域属于函数作用域, 在函数执行完后,作用域就会被清理,内存也会随之被回收,但是由于闭包函数是建立在函数内部的子函数, 由于其可访问上级作用域,即使上级函数执行完, 作用域也不会随之销毁, 这时的子函数(也就是闭包),便拥有了访问上级作用域中变量的权限,即使上级函数执行完后作用域内的值也不会被销毁。</p> <ul><li><p><strong>闭包的特性</strong>：</p> <ul><li><p>1、内部函数可以访问定义他们外部函数的参数和变量。(作用域链的向上查找，把外围的作用域中的变量值存储在内存中而不是在函数调用完毕后销毁)设计私有的方法和变量，避免全局变量的污染。</p> <p>1.1.闭包是密闭的容器，，类似于set、map容器，存储数据的</p> <p>1.2.闭包是一个对象，存放数据的格式为 key-value 形式</p></li> <li><p>2、函数嵌套函数</p></li> <li><p>3、本质是将函数内部和外部连接起来。优点是可以读取函数内部的变量，让这些变量的值始终保存在内存中，不会在函数被调用之后自动清除</p></li></ul></li> <li><p><strong>闭包形成的条件</strong>：</p> <ol><li>函数的嵌套</li> <li>内部函数引用外部函数的局部变量，延长外部函数的变量生命周期</li></ol></li> <li><p><strong>闭包的用途</strong>：</p> <ol><li>模仿块级作用域</li> <li>保护外部函数的变量 能够访问函数定义时所在的词法作用域(阻止其被回收)</li> <li>封装私有化变量</li> <li>创建模块</li></ol></li> <li><p><strong>闭包应用场景</strong></p> <p>闭包的两个场景，闭包的两大作用：<code>保存/保护</code>。 在开发中, 其实我们随处可见闭包的身影, 大部分前端JavaScript 代码都是“事件驱动”的,即一个事件绑定的回调方法; 发送ajax请求成功|失败的回调;setTimeout的延时回调;或者一个函数内部返回另一个匿名函数,这些都是闭包的应用。</p></li> <li><p><strong>闭包的优点</strong>：延长局部变量的生命周期</p></li> <li><p><strong>闭包缺点</strong>：会导致函数的变量一直保存在内存中，过多的闭包可能会导致内存泄漏</p></li></ul> <h2 id="js-中-this-的五种情况"><a href="#js-中-this-的五种情况" class="header-anchor">#</a> JS 中 this 的五种情况</h2> <ol><li>作为普通函数执行时，<code>this</code>指向<code>window</code>。</li> <li>当函数作为对象的方法被调用时，<code>this</code>就会指向<code>该对象</code>。</li> <li>构造器调用，<code>this</code>指向<code>返回的这个对象</code>。</li> <li>箭头函数 箭头函数的<code>this</code>绑定看的是<code>this所在函数定义在哪个对象下</code>，就绑定哪个对象。如果有嵌套的情况，则this绑定到最近的一层对象上。</li> <li>基于Function.prototype上的 <code>apply 、 call 和 bind</code>调用模式，这三个方法都可以显示的指定调用函数的 this 指向。<code>apply</code>接收参数的是数组，<code>call</code>接受参数列表，`` bind<code>方法通过传入一个对象，返回一个</code> this <code>绑定了传入对象的新函数。这个函数的</code>this<code>指向除了使用</code>new `时会被改变，其他情况下都不会改变。若为空默认是指向全局对象window。</li></ol> <h2 id="原型-原型链"><a href="#原型-原型链" class="header-anchor">#</a> 原型 &amp;&amp; 原型链</h2> <p><strong>原型关系：</strong></p> <ul><li>每个 class都有显示原型 prototype</li> <li>每个实例都有隐式原型 <em>proto</em></li> <li>实例的_proto_指向对应 class 的 prototype</li></ul> <p>‌ <strong>原型:</strong>  在 JS 中，每当定义一个对象（函数也是对象）时，对象中都会包含一些预定义的属性。其中每个<code>函数对象</code>都有一个<code>prototype</code> 属性，这个属性指向函数的<code>原型对象</code>。</p> <p>原型链：函数的原型链对象constructor默认指向函数本身，原型对象除了有原型属性外，为了实现继承，还有一个原型链指针__proto__,该指针是指向上一层的原型对象，而上一层的原型对象的结构依然类似。因此可以利用__proto__一直指向Object的原型对象上，而Object原型对象用Object.prototype.<strong>proto</strong> = null表示原型链顶端。如此形成了js的原型链继承。同时所有的js对象都有Object的基本防范</p> <p><strong>特点:</strong> <code>JavaScript</code>对象是通过引用来传递的，我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时，与之相关的对象也会继承这一改变。</p> <h2 id="new运算符的实现机制"><a href="#new运算符的实现机制" class="header-anchor">#</a> new运算符的实现机制</h2> <ol><li>首先创建了一个新的<code>空对象</code></li> <li><code>设置原型</code>，将对象的原型设置为函数的<code>prototype</code>对象。</li> <li>让函数的<code>this</code>指向这个对象，执行构造函数的代码（为这个新对象添加属性）</li> <li>判断函数的返回值类型，如果是值类型，返回创建的对象。如果是引用类型，就返回这个引用类型的对象。</li></ol> <h2 id="eventloop-事件循环"><a href="#eventloop-事件循环" class="header-anchor">#</a> EventLoop 事件循环</h2> <div class="language- extra-class"><pre class="language-text"><code>JS`是单线程的，为了防止一个函数执行时间过长阻塞后面的代码，所以会先将同步代码压入执行栈中，依次执行，将异步代码推入异步队列，异步队列又分为宏任务队列和微任务队列，因为宏任务队列的执行时间较长，所以微任务队列要优先于宏任务队列。微任务队列的代表就是，`Promise.then`，`MutationObserver`，宏任务的话就是`setImmediate setTimeout setInterval
</code></pre></div><p>JS运行的环境。一般为浏览器或者Node。 在浏览器环境中，有JS 引擎线程和渲染线程，且两个线程互斥。 Node环境中，只有JS 线程。 不同环境执行机制有差异，不同任务进入不同Event Queue队列。 当主程结束，先执行准备好微任务，然后再执行准备好的宏任务，一个轮询结束。</p> <h3 id="浏览器中的事件环-event-loop"><a href="#浏览器中的事件环-event-loop" class="header-anchor">#</a> <strong>浏览器中的事件环（Event Loop)</strong></h3> <p>事件环的运行机制是，先会执行栈中的内容，栈中的内容执行后执行微任务，微任务清空后再执行宏任务，先取出一个宏任务，再去执行微任务，然后在取宏任务清微任务这样不停的循环。</p> <ul><li><p>eventLoop 是由JS的宿主环境（浏览器）来实现的；</p></li> <li><p>事件循环可以简单的描述为以下四个步骤:</p> <ol><li>函数入栈，当Stack中执行到异步任务的时候，就将他丢给WebAPIs,接着执行同步任务,直到Stack为空；</li> <li>此期间WebAPIs完成这个事件，把回调函数放入队列中等待执行（微任务放到微任务队列，宏任务放到宏任务队列）</li> <li>执行栈为空时，Event Loop把微任务队列执行清空；</li> <li>微任务队列清空后，进入宏任务队列，取队列的第一项任务放入Stack(栈）中执行，执行完成后，查看微任务队列是否有任务，有的话，清空微任务队列。重复4，继续从宏任务中取任务执行，执行完成之后，继续清空微任务，如此反复循环，直至清空所有的任务。</li></ol> <p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/342e581223d2471d9484fc48beb9f8e1~tplv-k3u1fbpfcp-watermark.awebp" alt="事件循环流程"></p></li> <li><p>浏览器中的任务源(task):</p> <ul><li><code>宏任务(macrotask)</code>：
宿主环境提供的，比如浏览器
ajax、setTimeout、setInterval、setTmmediate(只兼容ie)、script、requestAnimationFrame、messageChannel、UI渲染、一些浏览器api</li> <li><code>微任务(microtask)</code>：
语言本身提供的，比如promise.then
then、queueMicrotask(基于then)、mutationObserver(浏览器提供)、messageChannel 、mutationObersve</li></ul></li></ul> <h3 id="node-环境中的事件环-event-loop"><a href="#node-环境中的事件环-event-loop" class="header-anchor">#</a> <strong>Node 环境中的事件环（Event Loop)</strong></h3> <p><code>Node</code>是基于V8引擎的运行在服务端的<code>JavaScript</code>运行环境，在处理高并发、I/O密集(文件操作、网络操作、数据库操作等)场景有明显的优势。虽然用到也是V8引擎，但由于服务目的和环境不同，导致了它的API与原生JS有些区别，其Event Loop还要处理一些I/O，比如新的网络连接等，所以Node的Event Loop(事件环机制)与浏览器的是不太一样。</p> <p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e362c1770f62428fbf3faabd99d2a64c~tplv-k3u1fbpfcp-watermark.awebp" alt="2020120317343116.png"> 执行顺序如下：</p> <ul><li><code>timers</code>: 计时器，执行setTimeout和setInterval的回调</li> <li><code>pending callbacks</code>: 执行延迟到下一个循环迭代的 I/O 回调</li> <li><code>idle, prepare</code>: 队列的移动，仅系统内部使用</li> <li><code>poll轮询</code>: 检索新的 I/O 事件;执行与 I/O 相关的回调。事实上除了其他几个阶段处理的事情，其他几乎所有的异步都在这个阶段处理。</li> <li><code>check</code>: 执行<code>setImmediate</code>回调，setImmediate在这里执行</li> <li><code>close callbacks</code>: 执行<code>close</code>事件的<code>callback</code>，一些关闭的回调函数，如：socket.on('close', ...)</li></ul> <h2 id="settimeout、promise、async-await-的区别"><a href="#settimeout、promise、async-await-的区别" class="header-anchor">#</a> setTimeout、Promise、Async/Await 的区别</h2> <ol><li><p>setTimeout</p> <p>settimeout的回调函数放到宏任务队列里，等到执行栈清空以后执行。</p></li> <li><p>Promise</p> <p>Promise本身是<strong>同步的立即执行函数</strong>， 当在executor中执行resolve或者reject的时候, 此时是异步操作， 会先执行then/catch等，当主栈完成后，才会去调用resolve/reject中存放的方法执行。</p> <div class="language-js extra-class"><pre class="language-js"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script start'</span><span class="token punctuation">)</span>
<span class="token keyword">let</span> promise1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">resolve</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'promise1'</span><span class="token punctuation">)</span>
    <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'promise1 end'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'promise2'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'settimeout'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script end'</span><span class="token punctuation">)</span>
<span class="token comment">// 输出顺序: script start-&gt;promise1-&gt;promise1 end-&gt;script end-&gt;promise2-&gt;settimeout</span>
复制代码
</code></pre></div></li> <li><p>async/await</p> <p>async 函数返回一个 Promise 对象，当函数执行的时候，一旦遇到 await 就会先返回，等到触发的异步操作完成，再执行函数体内后面的语句。可以理解为，是让出了线程，跳出了 async 函数体。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">async1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
   console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'async1 start'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">await</span> <span class="token function">async2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'async1 end'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">async2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'async2'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script start'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">async1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script end'</span><span class="token punctuation">)</span>

<span class="token comment">// 输出顺序：script start-&gt;async1 start-&gt;async2-&gt;script end-&gt;async1 end</span>
复制代码
</code></pre></div></li></ol> <h2 id="async-await-如何通过同步的方式实现异步"><a href="#async-await-如何通过同步的方式实现异步" class="header-anchor">#</a> Async/Await 如何通过同步的方式实现异步</h2> <p>Async/Await就是一个<strong>自执行</strong>的generate函数。利用generate函数的特性把异步的代码写成“同步”的形式,第一个请求的返回值作为后面一个请求的参数,其中每一个参数都是一个promise对象.</p> <h2 id="介绍节流防抖原理、区别以及应用"><a href="#介绍节流防抖原理、区别以及应用" class="header-anchor">#</a> 介绍节流防抖原理、区别以及应用</h2> <p><code>节流</code>：事件触发后，规定时间内，事件处理函数不能再次被调用。也就是说在规定的时间内，函数只能被调用一次，且是最先被触发调用的那次。</p> <p><code>防抖</code>：多次触发事件，事件处理函数只能执行一次，并且是在触发操作结束时执行。也就是说，当一个事件被触发准备执行事件函数前，会等待一定的时间（这时间是码农自己去定义的，比如 1 秒），如果没有再次被触发，那么就执行，如果被触发了，那就本次作废，重新从新触发的时间开始计算，并再次等待 1 秒，直到能最终执行！</p> <p><code>使用场景</code>：
节流：滚动加载更多、搜索框搜的索联想功能、高频点击、表单重复提交……
防抖：搜索框搜索输入，并在输入完以后自动搜索、手机号，邮箱验证输入检测、窗口大小 resize 变化后，再重新渲染。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/**
 * 节流函数 一个函数执行一次后，只有大于设定的执行周期才会执行第二次。有个需要频繁触发的函数，出于优化性能的角度，在规定时间内，只让函数触发的第一次生效，后面的不生效。
 * @param fn要被节流的函数
 * @param delay规定的时间
 */</span>
<span class="token keyword">function</span> <span class="token function">throttle</span><span class="token punctuation">(</span><span class="token parameter">fn<span class="token punctuation">,</span> delay</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">//记录上一次函数触发的时间</span>
    <span class="token keyword">var</span> lastTime <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token comment">//记录当前函数触发的时间</span>
        <span class="token keyword">var</span> nowTime <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>nowTime <span class="token operator">-</span> lastTime <span class="token operator">&gt;</span> delay<span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token comment">//修正this指向问题</span>
            <span class="token function">fn</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">//同步执行结束时间</span>
            lastTime <span class="token operator">=</span> nowTime<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

document<span class="token punctuation">.</span>onscroll <span class="token operator">=</span> <span class="token function">throttle</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'scllor事件被触发了'</span> <span class="token operator">+</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 

<span class="token comment">/**
 * 防抖函数  一个需要频繁触发的函数，在规定时间内，只让最后一次生效，前面的不生效
 * @param fn要被节流的函数
 * @param delay规定的时间
 */</span>
<span class="token keyword">function</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">fn<span class="token punctuation">,</span> delay</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">//记录上一次的延时器</span>
    <span class="token keyword">var</span> timer <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
       <span class="token comment">//清除上一次的演示器</span>
        <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//重新设置新的延时器</span>
        timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token comment">//修正this指向问题</span>
            <span class="token function">fn</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span> delay<span class="token punctuation">)</span><span class="token punctuation">;</span> 
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'btn'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>onclick <span class="token operator">=</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'按钮被点击了'</span> <span class="token operator">+</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
复制代码
</code></pre></div><h2 id="简述mvvm"><a href="#简述mvvm" class="header-anchor">#</a> 简述MVVM</h2> <p><strong>什么是MVVM？</strong></p> <p><code>视图模型双向绑定</code>，是<code>Model-View-ViewModel</code>的缩写，也就是把<code>MVC</code>中的<code>Controller</code>演变成<code>ViewModel。Model</code>层代表数据模型，<code>View</code>代表UI组件，<code>ViewModel</code>是<code>View</code>和<code>Model</code>层的桥梁，数据会绑定到<code>viewModel</code>层并自动将数据渲染到页面中，视图变化的时候会通知<code>viewModel</code>层更新数据。以前是操作DOM结构更新视图，现在是<code>数据驱动视图</code>。</p> <p><strong>MVVM的优点：</strong></p> <p>1.<code>低耦合</code>。视图（View）可以独立于Model变化和修改，一个Model可以绑定到不同的View上，当View变化的时候Model可以不变化，当Model变化的时候View也可以不变；
2.<code>可重用性</code>。你可以把一些视图逻辑放在一个Model里面，让很多View重用这段视图逻辑。
3.<code>独立开发</code>。开发人员可以专注于业务逻辑和数据的开发(ViewModel)，设计人员可以专注于页面设计。
4.<code>可测试</code>。</p> <h2 id="vue底层实现原理"><a href="#vue底层实现原理" class="header-anchor">#</a> Vue底层实现原理</h2> <p>vue.js是采用数据劫持结合发布者-订阅者模式的方式，通过Object.defineProperty()来劫持各个属性的setter和getter，在数据变动时发布消息给订阅者，触发相应的监听回调
Vue是一个典型的MVVM框架，模型（Model）只是普通的javascript对象，修改它则试图（View）会自动更新。这种设计让状态管理变得非常简单而直观</p> <p><strong>Observer（数据监听器）</strong> : Observer的核心是通过Object.defineProprtty()来监听数据的变动，这个函数内部可以定义setter和getter，每当数据发生变化，就会触发setter。这时候Observer就要通知订阅者，订阅者就是Watcher</p> <p><strong>Watcher（订阅者）</strong> : Watcher订阅者作为Observer和Compile之间通信的桥梁，主要做的事情是：</p> <ol><li>在自身实例化时往属性订阅器(dep)里面添加自己</li> <li>自身必须有一个update()方法</li> <li>待属性变动dep.notice()通知时，能调用自身的update()方法，并触发Compile中绑定的回调</li></ol> <p><strong>Compile（指令解析器）</strong> : Compile主要做的事情是解析模板指令，将模板中变量替换成数据，然后初始化渲染页面视图，并将每个指令对应的节点绑定更新函数，添加鉴定数据的订阅者，一旦数据有变动，收到通知，更新试图</p> <h2 id="谈谈对vue生命周期的理解"><a href="#谈谈对vue生命周期的理解" class="header-anchor">#</a> 谈谈对vue生命周期的理解？</h2> <p>每个<code>Vue</code>实例在创建时都会经过一系列的初始化过程，<code>vue</code>的生命周期钩子，就是说在达到某一阶段或条件时去触发的函数，目的就是为了完成一些动作或者事件</p> <h3 id="_1-页面生命周期"><a href="#_1-页面生命周期" class="header-anchor">#</a> 1. 页面生命周期</h3> <ul><li><code>create阶段</code>：vue实例被创建
<code>beforeCreate</code>: 创建前，此时data和methods中的数据都还没有初始化
<code>created</code>： 创建完毕，data中有值，未挂载</li> <li><code>mount阶段</code>： vue实例被挂载到真实DOM节点
<code>beforeMount</code>：可以发起服务端请求，去数据
<code>mounted</code>: 此时可以操作DOM</li> <li><code>update阶段</code>：当vue实例里面的data数据变化时，触发组件的重新渲染
<code>beforeUpdate</code> :更新前
<code>updated</code>：更新后</li> <li><code>destroy阶段</code>：vue实例被销毁
<code>beforeDestroy</code>：实例被销毁前，此时可以手动销毁一些方法
<code>destroyed</code>:销毁后</li></ul> <h3 id="_2-组件生命周期"><a href="#_2-组件生命周期" class="header-anchor">#</a> 2. 组件生命周期</h3> <p>生命周期（父子组件） 父组件beforeCreate --&gt; 父组件created --&gt; 父组件beforeMount --&gt; 子组件beforeCreate --&gt; 子组件created --&gt; 子组件beforeMount --&gt; 子组件 mounted --&gt; 父组件mounted --&gt;父组件beforeUpdate --&gt;子组件beforeDestroy--&gt; 子组件destroyed --&gt; 父组件updated</p> <p><strong>加载渲染过程</strong> 父beforeCreate-&gt;父created-&gt;父beforeMount-&gt;子beforeCreate-&gt;子created-&gt;子beforeMount-&gt;子mounted-&gt;父mounted</p> <p><strong>挂载阶段</strong> 父created-&gt;子created-&gt;子mounted-&gt;父mounted</p> <p><strong>父组件更新阶段</strong> 父beforeUpdate-&gt;父updated</p> <p><strong>子组件更新阶段</strong> 父beforeUpdate-&gt;子beforeUpdate-&gt;子updated-&gt;父updated</p> <p><strong>销毁阶段</strong> 父beforeDestroy-&gt;子beforeDestroy-&gt;子destroyed-&gt;父destroyed</p> <h2 id="vue中computed与watch区别"><a href="#vue中computed与watch区别" class="header-anchor">#</a> Vue中computed与watch区别</h2> <p>通俗来讲，既能用 computed 实现又可以用 watch 监听来实现的功能，推荐用 computed， 重点在于 computed 的缓存功能 computed 计算属性是用来声明式的描述一个值依赖了其它的值，当所依赖的值或者变量 改变时，计算属性也会跟着改变； watch 监听的是已经在 data 中定义的变量，当该变量变化时，会触发 watch 中的方法。</p> <p><strong>watch 属性监听</strong> 是一个对象，键是需要观察的属性，值是对应回调函数，主要用来监听某些特定数据的变化，从而进行某些具体的业务逻辑操作,监听属性的变化，需要在数据变化时执行异步或开销较大的操作时使用</p> <p><strong>computed 计算属性</strong> 属性的结果会被<code>缓存</code>，当<code>computed</code>中的函数所依赖的属性没有发生改变的时候，那么调用当前函数的时候结果会从缓存中读取。除非依赖的响应式属性变化时才会重新计算，主要当做属性来使用 <code>computed</code>中的函数必须用<code>return</code>返回最终的结果 <code>computed</code>更高效，优先使用。<code>data 不改变，computed 不更新。</code></p> <p><strong>使用场景</strong> <code>computed</code>：当一个属性受多个属性影响的时候使用，例：购物车商品结算功能 <code>watch</code>：当一条数据影响多条数据的时候使用，例：搜索数据</p> <h3 id="vue组件中的data为什么是一个函数"><a href="#vue组件中的data为什么是一个函数" class="header-anchor">#</a> Vue组件中的data为什么是一个函数？</h3> <ol><li>一个组件被复用多次的话，也就会创建多个实例。本质上，这些实例用的都是同一个构造函数。</li> <li>如果data是对象的话，对象属于引用类型，会影响到所有的实例。所以为了保证组件不同的实例之间data不冲突，data必须是一个函数。</li></ol> <h3 id="vue中为什么v-for和v-if不建议用在一起"><a href="#vue中为什么v-for和v-if不建议用在一起" class="header-anchor">#</a> Vue中为什么v-for和v-if不建议用在一起</h3> <ol><li>当 v-for 和 v-if 处于同一个节点时，v-for 的优先级比 v-if 更高，这意味着 v-if 将分别重复运行于每个 v-for 循环中。如果要遍历的数组很大，而真正要展示的数据很少时，这将造成很大的性能浪费</li> <li>这种场景建议使用 computed，先对数据进行过滤</li></ol> <h2 id="react-vue-项目中-key-的作用"><a href="#react-vue-项目中-key-的作用" class="header-anchor">#</a> React/Vue 项目中 key 的作用</h2> <ul><li><p>key的作用是为了在diff算法执行时更快的找到对应的节点，<code>提高diff速度，更高效的更新虚拟DOM</code>;</p> <p>vue和react都是采用diff算法来对比新旧虚拟节点，从而更新节点。在vue的diff函数中，会根据新节点的key去对比旧节点数组中的key，从而找到相应旧节点。如果没找到就认为是一个新增节点。而如果没有key，那么就会采用遍历查找的方式去找到对应的旧节点。一种一个map映射，另一种是遍历查找。相比而言。map映射的速度更快。</p></li> <li><p>为了在数据变化时强制更新组件，以避免<code>“就地复用”</code>带来的副作用。</p> <p>当 Vue.js 用 <code>v-for</code> 更新已渲染过的元素列表时，它默认用“就地复用”策略。如果数据项的顺序被改变，Vue 将不会移动 DOM 元素来匹配数据项的顺序，而是简单复用此处每个元素，并且确保它在特定索引下显示已被渲染过的每个元素。重复的key会造成渲染错误。</p></li></ul> <h2 id="vue组件的通信方式"><a href="#vue组件的通信方式" class="header-anchor">#</a> Vue组件的通信方式</h2> <ul><li><p><code>props</code>/<code>$emit</code> 父子组件通信</p> <p>父-&gt;子<code>props</code>，子-&gt;父 <code>$on、$emit</code> 获取父子组件实例 <code>parent、children</code> <code>Ref</code>获取实例的方式调用组件的属性或者方法 父-&gt;子孙 <code>Provide、inject</code> 官方不推荐使用，但是写组件库时很常用</p></li> <li><p><code>$emit</code>/<code>$on</code> 自定义事件 兄弟组件通信</p> <p><code>Event Bus</code> 实现跨组件通信 <code>Vue.prototype.$bus = new Vue()</code> 自定义事件</p></li> <li><p>vuex 跨级组件通信</p> <p>Vuex、<code>$attrs、$listeners</code> <code>Provide、inject</code></p></li></ul> <h2 id="nexttick的实现"><a href="#nexttick的实现" class="header-anchor">#</a> nextTick的实现</h2> <ol><li><code>nextTick</code>是<code>Vue</code>提供的一个全局<code>API</code>,是在下次<code>DOM</code>更新循环结束之后执行延迟回调，在修改数据之后使用<code>$nextTick</code>，则可以在回调中获取更新后的<code>DOM</code>；</li> <li>Vue在更新DOM时是异步执行的。只要侦听到数据变化，<code>Vue</code>将开启1个队列，并缓冲在同一事件循环中发生的所有数据变更。如果同一个<code>watcher</code>被多次触发，只会被推入到队列中-次。这种在缓冲时去除重复数据对于避免不必要的计算和<code>DOM</code>操作是非常重要的。<code>nextTick</code>方法会在队列中加入一个回调函数，确保该函数在前面的dom操作完成后才调用；</li> <li>比如，我在干什么的时候就会使用nextTick，传一个回调函数进去，在里面执行dom操作即可；</li> <li>我也有简单了解<code>nextTick</code>实现，它会在<code>callbacks</code>里面加入我们传入的函数，然后用<code>timerFunc</code>异步方式调用它们，首选的异步方式会是<code>Promise</code>。这让我明白了为什么可以在<code>nextTick</code>中看到<code>dom</code>操作结果。</li></ol> <h2 id="nexttick的实现原理是什么"><a href="#nexttick的实现原理是什么" class="header-anchor">#</a> nextTick的实现原理是什么？</h2> <p>在下次 DOM 更新循环结束之后执行延迟回调，在修改数据之后立即使用 nextTick 来获取更新后的 DOM。 nextTick主要使用了宏任务和微任务。 根据执行环境分别尝试采用Promise、MutationObserver、setImmediate，如果以上都不行则采用setTimeout定义了一个异步方法，多次调用nextTick会将方法存入队列中，通过这个异步方法清空当前队列。</p> <h2 id="插槽"><a href="#插槽" class="header-anchor">#</a> 插槽</h2> <p>具名插槽、匿名插槽、作用域插槽</p> <p>vue中的插槽是一个非常好用的东西slot说白了就是一个占位的 在vue当中插槽包含三种一种是默认插槽（匿名）一种是具名插槽还有一种就是作用域插槽 匿名插槽就是没有名字的只要默认的都填到这里具名插槽指的是具有名字的</p> <h2 id="keep-alive的实现"><a href="#keep-alive的实现" class="header-anchor">#</a> keep-alive的实现</h2> <p><strong>作用</strong>：实现组件缓存，保持这些组件的状态，以避免反复渲染导致的性能问题。 需要缓存组件 频繁切换，不需要重复渲染</p> <p><strong>场景</strong>：tabs标签页 后台导航，vue性能优化</p> <p><strong>原理</strong>：<code>Vue.js</code>内部将<code>DOM</code>节点抽象成了一个个的<code>VNode</code>节点，<code>keep-alive</code>组件的缓存也是基于<code>VNode</code>节点的而不是直接存储<code>DOM</code>结构。它将满足条件<code>（pruneCache与pruneCache）</code>的组件在<code>cache</code>对象中缓存起来，在需要重新渲染的时候再将<code>vnode</code>节点从<code>cache</code>对象中取出并渲染。</p> <h2 id="mixin"><a href="#mixin" class="header-anchor">#</a> mixin</h2> <p>mixin 项目变得复杂的时候，多个组件间有重复的逻辑就会用到mixin 多个组件有相同的逻辑，抽离出来 mixin并不是完美的解决方案，会有一些问题 vue3提出的Composition API旨在解决这些问题【追求完美是要消耗一定的成本的，如开发成本】 场景：PC端新闻列表和详情页一样的右侧栏目，可以使用mixin进行混合 劣势：1.变量来源不明确，不利于阅读 2.多mixin可能会造成命名冲突 3.mixin和组件可能出现多对多的关系，使得项目复杂度变高</p> <h2 id="vuex的理解及使用场景"><a href="#vuex的理解及使用场景" class="header-anchor">#</a> Vuex的理解及使用场景</h2> <p>Vuex 是一个专为 Vue 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store（仓库）。</p> <ol><li>Vuex 的状态存储是响应式的；当 Vue 组件从 store 中读取状态的时候，若 store 中的状态发生变化，那么相应的组件也会相应地得到高效更新</li> <li>改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation， 这样使得我们可以方便地跟踪每一个状态的变化 Vuex主要包括以下几个核心模块：</li></ol> <ul><li>State：定义了应用的状态数据</li> <li>Getter：在 store 中定义“getter”（可以认为是 store 的计算属性），就像计算属性一样，getter 的返回值会根据它的依赖被缓存起来， 且只有当它的依赖值发生了改变才会被重新计算</li> <li>Mutation：是唯一更改 store 中状态的方法，且必须是同步函数</li> <li>Action：用于提交 mutation，而不是直接变更状态，可以包含任意异步操作 5. Module：允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中</li></ul> <p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a7249773a1634f779c48f3f0ffabf968~tplv-k3u1fbpfcp-watermark.awebp" alt="img"></p> <h2 id="项目优化"><a href="#项目优化" class="header-anchor">#</a> 项目优化</h2> <p><code>移除生产环境的控制台打印</code>。方案很多，esling+pre-commit、使用插件自动去除，插件包括babel-plugin-transform-remove-console、uglifyjs-webpack-plugin、terser-webpack-plugin。最后选择了terser-webpack-plugin，脚手架vue-cli用这个插件来开启缓存和多线程打包，无需安装额外的插件，仅需在configureWebpack中设置terser插件的drop_console为true即可。最好还是养成良好的代码习惯，在开发基本完成后去掉无用的console，vscode中的turbo console就蛮好的。</p> <p><code>第三方库的按需加载</code>。echarts，官方文档里是使用配置文件指定使用的模块，另一种使用babel-plugin-equire实现按需加载。element-ui使用babel-plugin-component实现按需引入。</p> <p>公有样式，比如对element-ui部分组件（如弹框、表格、下拉选框等）<code>样式的统一调整</code>。公共组件，比如date-picker、upload-file等在element-ui提供的组件基本上做进一步的封装。自定义组件包括preview-file、搜索框等。</p> <p>前后端数据交换方面，推动项目组使用蓝湖、接口文档，与后端同学协商，规范后台数据返回。</p> <p>雅虎军规提到的，<code>避免css表达式、滤镜，较少DOM操作，优化图片、精灵图，避免图片空链接等</code>。</p> <p><code>性能问题：页面加载性能、动画性能、操作性能</code>。Performance API，记录性能数据。</p> <p>winter重学前端 优化技术方案：</p> <p>缓存：<code>客户端控制的强缓存策略</code>。</p> <p><code>降低请求成本</code>：DNS 由客户端控制，隔一段时间主动请求获取域名IP，不走系统DNS（完全看不懂）。TCP/TLS连接复用，服务器升级到HTTP2，尽量合并域名。</p> <p><code>减少请求数</code>：JS、CSS打包到HTML。JS控制图片异步加载、懒加载。小型图片使用data-uri。</p> <p><code>较少传输体积</code>：尽量使用SVG\gradient代替图片。根据机型和网络状况控制图片清晰度。对低清晰度图片使用锐化来提升体验。设计上避免大型背景图。</p> <p><code>使用CDN加速</code>，内容分发网络，是建立再承载网基础上的虚拟分布式网络，能够将源站内容缓存到全国或全球的节点服务器上。用户就近获取内容，提高了资源的访问速度，分担源站压力。</p></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">更新时间:</span> <span class="time">11/11/2021, 8:14:15 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/technology/js_higher.html" class="prev">
        JS高级知识点
      </a></span> <span class="next"><a href="/technology/eight_002.html">
        八股文-002
      </a>
      →
    </span></p></div> </main></div><div class="global-ui"><!----></div></div>
    <script src="/assets/js/app.bf44e39b.js" defer></script><script src="/assets/js/2.db7a59af.js" defer></script><script src="/assets/js/266.97118d6c.js" defer></script>
  </body>
</html>
